<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0,viewport-fit=cover"><title>TCP协议 | Depicter</title><meta name="author" content="fanhao"><meta name="copyright" content="fanhao"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="ffffff"><meta name="description" content="TCP&#x2F;IP协议应用层 Application Layer应用层的本质是规定了应用程序之间如何相互传递报文 传输层 Transportation Layer对传输行为进行控制，而不是将数据从一台主机传送到另一台 客户端和服务端进程的逻辑连接 网络互连层 Internet Layer提供了主机到主机的通信，将传输层产生的数据包封装成分组数据包发送到目标主机，并提供路由选择的能力。 IP 协">
<meta property="og:type" content="article">
<meta property="og:title" content="TCP协议">
<meta property="og:url" content="https://crappier.github.io/2024/03/10/TCP%E5%8D%8F%E8%AE%AE/index.html">
<meta property="og:site_name" content="Depicter">
<meta property="og:description" content="TCP&#x2F;IP协议应用层 Application Layer应用层的本质是规定了应用程序之间如何相互传递报文 传输层 Transportation Layer对传输行为进行控制，而不是将数据从一台主机传送到另一台 客户端和服务端进程的逻辑连接 网络互连层 Internet Layer提供了主机到主机的通信，将传输层产生的数据包封装成分组数据包发送到目标主机，并提供路由选择的能力。 IP 协">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://crappier.github.io/img/cover/cover_9.jpg">
<meta property="article:published_time" content="2024-03-10T08:15:52.000Z">
<meta property="article:modified_time" content="2024-03-24T07:52:44.143Z">
<meta property="article:author" content="fanhao">
<meta property="article:tag" content="计算机网络">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://crappier.github.io/img/cover/cover_9.jpg"><link rel="shortcut icon" href="/img/dinosaur.png"><link rel="canonical" href="https://crappier.github.io/2024/03/10/TCP%E5%8D%8F%E8%AE%AE/index.html"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox/fancybox.min.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: undefined,
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":false,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: true,
    post: true
  },
  runtime: '天',
  dateSuffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: false,
  isAnchor: false,
  percent: {
    toc: true,
    rightside: false,
  }
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: 'TCP协议',
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2024-03-24 15:52:44'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
    win.getCSS = (url,id = false) => new Promise((resolve, reject) => {
      const link = document.createElement('link')
      link.rel = 'stylesheet'
      link.href = url
      if (id) link.id = id
      link.onerror = reject
      link.onload = link.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        link.onload = link.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(link)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', 'ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const detectApple = () => {
      if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
    })(window)</script><meta name="generator" content="Hexo 6.3.0"></head><body><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="/img/avatar.jpg" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">10</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">5</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">0</div></a></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 主页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于笔者</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg fixed" id="page-header" style="background-image: url('/img/cover/cover_9.jpg')"><nav id="nav"><span id="blog-info"><a href="/" title="Depicter"><span class="site-name">Depicter</span></a></span><div id="menus"><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 主页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于笔者</span></a></div></div><div id="toggle-menu"><a class="site-page" href="javascript:void(0);"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">TCP协议</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2024-03-10T08:15:52.000Z" title="发表于 2024-03-10 16:15:52">2024-03-10</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2024-03-24T07:52:44.143Z" title="更新于 2024-03-24 15:52:44">2024-03-24</time></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="TCP协议"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><h1 id="TCP-x2F-IP协议"><a href="#TCP-x2F-IP协议" class="headerlink" title="TCP&#x2F;IP协议"></a>TCP&#x2F;IP协议</h1><h2 id="应用层-Application-Layer"><a href="#应用层-Application-Layer" class="headerlink" title="应用层 Application Layer"></a>应用层 Application Layer</h2><p>应用层的本质是规定了应用程序之间如何相互传递报文</p>
<h2 id="传输层-Transportation-Layer"><a href="#传输层-Transportation-Layer" class="headerlink" title="传输层 Transportation Layer"></a>传输层 Transportation Layer</h2><p>对传输行为进行控制，而不是将数据从一台主机传送到另一台</p>
<p>客户端和服务端进程的逻辑连接</p>
<h2 id="网络互连层-Internet-Layer"><a href="#网络互连层-Internet-Layer" class="headerlink" title="网络互连层 Internet Layer"></a>网络互连层 Internet Layer</h2><p>提供了主机到主机的通信，将传输层产生的数据包封装成分组数据包发送到目标主机，并提供路由选择的能力。</p>
<p>IP 协议是一个无连接的协议，不具备重发机制，TCP 协议复杂的原因之一就是因为 TCP 基于 IP 协议。</p>
<h2 id="网络访问层-Network-Access-Layer"><a href="#网络访问层-Network-Access-Layer" class="headerlink" title="网络访问层 Network Access Layer"></a>网络访问层 Network Access Layer</h2><p>以太网、Wifi、蓝牙工作在这一层</p>
<h2 id="分层的优势"><a href="#分层的优势" class="headerlink" title="分层的优势"></a>分层的优势</h2><ul>
<li>各层独立</li>
<li>灵活性更好</li>
<li>易于测试和维护</li>
<li>促进标准化</li>
</ul>
<h1 id="TCP协议"><a href="#TCP协议" class="headerlink" title="TCP协议"></a>TCP协议</h1><p>TCP 是一个可靠的、面向连接的、基于字节流、全双工的协议。</p>
<h2 id="面向连接"><a href="#面向连接" class="headerlink" title="面向连接"></a>面向连接</h2><p>在正式建立会话之前，需要事先建立通信渠道</p>
<h2 id="IP协议"><a href="#IP协议" class="headerlink" title="IP协议"></a>IP协议</h2><p>IP 是一种尽力而为、不可靠的无连接服务</p>
<p>不保证顺序、不保证包是否重复，甚至不保证包是否会到达接收者</p>
<p>接收上层的包，将其封装为 IP 分组，然后进行发送。一旦发送出去，IP 就不用在关心这个 IP 分组了。</p>
<h2 id="TCP协议是“可靠的”"><a href="#TCP协议是“可靠的”" class="headerlink" title="TCP协议是“可靠的”"></a>TCP协议是“可靠的”</h2><p>TCP通过：校验和[不被修改]、序列号[顺序正确]、确认与超时重传[数据不会丢失]  以保证“可靠性”</p>
<h2 id="TCP是一个流协议"><a href="#TCP是一个流协议" class="headerlink" title="TCP是一个流协议"></a>TCP是一个流协议</h2><blockquote>
<p>  流：没有固定的报文边界</p>
</blockquote>
<p>接收端读取 recv 时，不对数据量做任何假设</p>
<p>TCP 是一个流协议，通过 IP 分组发送时，分组发送的数据大小与 send 调用发送的数据大小并没有直接关系，接收端也没有可靠的方式分辨数据是否分组</p>
<h2 id="记录边界标识"><a href="#记录边界标识" class="headerlink" title="记录边界标识"></a>记录边界标识</h2><ul>
<li>用特殊的结束符 <code>\r\n</code></li>
<li>给报文加上首部，记录报文长度</li>
</ul>
<h2 id="TCP是全双工的协议"><a href="#TCP是全双工的协议" class="headerlink" title="TCP是全双工的协议"></a>TCP是全双工的协议</h2><p>全双工通信，双方可同时收与发</p>
<p>两条线路相互独立</p>
<h2 id="TCP-可靠性"><a href="#TCP-可靠性" class="headerlink" title="TCP 可靠性"></a>TCP 可靠性</h2><p>内核层可靠，应用层不一定可靠</p>
<h1 id="WireShark"><a href="#WireShark" class="headerlink" title="WireShark"></a>WireShark</h1><h2 id="抓包"><a href="#抓包" class="headerlink" title="抓包"></a>抓包</h2><p>一次请求的过程: curl -v <a target="_blank" rel="noopener" href="https://www.baidu.com/">https://www.baidu.com</a></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">GET / HTTP1.1</span><br><span class="line">Host:www.baidu.com</span><br><span class="line">User-Agent: curl/7.64.1</span><br><span class="line">Accept:*/*</span><br></pre></td></tr></table></figure>

<p>WAF、网关</p>
<ul>
<li>快速理解黑盒系统网络问题，缩小故障验证范围</li>
<li>辅助快速理解网络协议</li>
<li>沟通高效</li>
</ul>
<h2 id="WireShark使用"><a href="#WireShark使用" class="headerlink" title="WireShark使用"></a>WireShark使用</h2><h3 id="捕获过滤器-capture-filter"><a href="#捕获过滤器-capture-filter" class="headerlink" title="捕获过滤器 capture filter"></a>捕获过滤器 capture filter</h3><p>抓取满足特定条件的包，丢弃不感兴趣的包</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240305094822028.png" alt="image-20240305094822028"></p>
<h3 id="显示过滤-display-filter"><a href="#显示过滤-display-filter" class="headerlink" title="显示过滤 display filter"></a>显示过滤 display filter</h3><blockquote>
<p>  <a target="_blank" rel="noopener" href="https://gitlab.com/wireshark/wireshark/-/wikis/DisplayFilters">DisplayFilters · Wiki · Wireshark Foundation &#x2F; Wireshark · GitLab — DisplayFilters · Wiki · Wireshark Foundation &#x2F; Wireshark · GitLab</a></p>
</blockquote>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240305095206424.png" alt="image-20240305095206424"></p>
<ul>
<li>协议过滤器(ip&#x2F;tcp&#x2F;udp&#x2F;arp&#x2F;icmp)</li>
<li>应用过滤器(dns&#x2F;ftp&#x2F;nfs&#x2F;http)</li>
<li>字段过滤器(http.host&#x2F;dns.qry.name)</li>
<li>&#x3D;&#x3D; 或者 eq</li>
<li>!&#x3D; 或者 ne</li>
<li>&gt; 或者 gt</li>
<li>&lt; 或者 lt</li>
<li>包含 contains</li>
<li>匹配 matches</li>
</ul>
<h3 id="常用的显示过滤器"><a href="#常用的显示过滤器" class="headerlink" title="常用的显示过滤器"></a>常用的显示过滤器</h3><h4 id="TCP相关"><a href="#TCP相关" class="headerlink" title="TCP相关"></a>TCP相关</h4><p>tcp.flags.syn &#x3D;&#x3D; 1：过滤 SYN 包</p>
<p>tcp.flags.reset &#x3D;&#x3D; 1：过滤 RST 包</p>
<p>tcp.analysis.retransmission：过滤重传包</p>
<p>tcp.analysis.zero_window：零窗口</p>
<h4 id="HTTP相关"><a href="#HTTP相关" class="headerlink" title="HTTP相关"></a>HTTP相关</h4><p>http.host &#x3D;&#x3D; t.tt：过滤指定域名的 http 包</p>
<p>http.response.code &#x3D;&#x3D; 302：过滤 http 响应状态码为 302 的数据包</p>
<p>http.request.method &#x3D;&#x3D; POST：过滤所有请求方式为 POST 的 http 请求包</p>
<p>http.transfer_encoding &#x3D;&#x3D; “chunked” 根据tannsfer_encoding 过滤</p>
<p>http.request.uri conatins “&#x2F;app&#x2F;query”：过滤 http 请求包含指定路径的请求</p>
<h4 id="通信延迟常用过滤器"><a href="#通信延迟常用过滤器" class="headerlink" title="通信延迟常用过滤器"></a>通信延迟常用过滤器</h4><blockquote>
<p>  单位: s</p>
</blockquote>
<p>http.time &gt; 0.5：请求发出到收到第一个响应包的时间间隔，用这个条件来过滤 http 的时延</p>
<p>tcp.time_delta &gt; 0.3：tcp 某连接中两次包的时间间隔，用于分析 TCP 的时延</p>
<p>dns.time &gt; 0.5：dns 的查询耗时</p>
<h4 id="抓取-HTTPS-包"><a href="#抓取-HTTPS-包" class="headerlink" title="抓取 HTTPS 包"></a>抓取 HTTPS 包</h4><ul>
<li>设置系统环境变量 <code>SSLKEYLOGFILE</code></li>
</ul>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240305105659382.png" alt="image-20240305105659382"></p>
<ul>
<li>WireShark 中设置 SSL 选项</li>
</ul>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240305105743139.png" alt="image-20240305105743139"></p>
<ul>
<li>重启浏览器即可进行抓包</li>
</ul>
<h4 id="WireShark写插件"><a href="#WireShark写插件" class="headerlink" title="WireShark写插件"></a>WireShark写插件</h4><p>wireshark + lua</p>
<p><a target="_blank" rel="noopener" href="https://juejin.cn/post/6844904085125070861">https://juejin.cn/post/6844904085125070861</a></p>
<p><a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/114669991">https://zhuanlan.zhihu.com/p/114669991</a></p>
<p><a target="_blank" rel="noopener" href="https://www.wireshark.org/docs/wsdg_html_chunked/">https://www.wireshark.org/docs/wsdg_html_chunked/</a></p>
<h1 id="TCP-协议的首部字段"><a href="#TCP-协议的首部字段" class="headerlink" title="TCP 协议的首部字段"></a>TCP 协议的首部字段</h1><p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240305121911161.png" alt="image-20240305121911161"></p>
<h2 id="序列号-sequence-number"><a href="#序列号-sequence-number" class="headerlink" title="序列号 sequence number"></a>序列号 sequence number</h2><p>序列号是一个 32 位的无符号整数，0-2^32^-1</p>
<p>在建立连接之时，通信双方都会各自选择一个序列号，称为初始序列号</p>
<h2 id="三次握手的-ISN-交换"><a href="#三次握手的-ISN-交换" class="headerlink" title="三次握手的 ISN 交换"></a>三次握手的 ISN 交换</h2><p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240305122558072.png" alt="image-20240305122558072"></p>
<h2 id="序列号回绕"><a href="#序列号回绕" class="headerlink" title="序列号回绕"></a>序列号回绕</h2><h2 id="确认号-ack"><a href="#确认号-ack" class="headerlink" title="确认号 ack"></a>确认号 ack</h2><p>告知对方下一个期望接收的序列号，小于此确认号的所有字节都已经收到</p>
<ul>
<li>不是所有的包都需要确认</li>
<li>不是收到了数据包就立马确认，可以延迟一会儿再确认</li>
<li>ack 包本身不需要确认，否则会进入死循环</li>
<li>确认号永远表示 ：<strong>小于此确认号的字节都已经收到</strong></li>
</ul>
<h2 id="TCP-Flags"><a href="#TCP-Flags" class="headerlink" title="TCP Flags"></a>TCP Flags</h2><p>标记位</p>
<h2 id="窗口大小"><a href="#窗口大小" class="headerlink" title="窗口大小"></a>窗口大小</h2><ul>
<li>最大只有 65535字节(64KB)</li>
</ul>
<h2 id="TCP-窗口缩放-window-scale"><a href="#TCP-窗口缩放-window-scale" class="headerlink" title="TCP 窗口缩放 window scale"></a>TCP 窗口缩放 window scale</h2><p>64K * scaling factor</p>
<h2 id="可选项-options、padding"><a href="#可选项-options、padding" class="headerlink" title="可选项 options、padding"></a>可选项 options、padding</h2><ul>
<li>mss：最大段大小选项，TCP 允许从对方接收的最大报文段</li>
<li>sack：选择确认选项</li>
<li>window scale：窗口缩放选项</li>
</ul>
<h1 id="端口号"><a href="#端口号" class="headerlink" title="端口号"></a>端口号</h1><p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240305145240667.png" alt="image-20240305145240667"></p>
<ul>
<li>熟知端口号<ul>
<li>由专门的机构 IANA 分配和控制，范围是0-1023，如 HTTP 80，HTTPS 443，SSH 22</li>
</ul>
</li>
<li>已登记端口号<ul>
<li>已登录的端口不受 IANA控制，不过由 IANA 登记，并提供它们的使用情况清单。范围是 1024-49151，如MySQL 3306，Rdis 6379，MongoDB 27017</li>
</ul>
</li>
<li>临时端口号<ul>
<li>如果应用程序没有调用 bind() 函数将 socket 绑定到特定的端口上，那么 TCP 和 UDP会为该 socket 分配一个唯一的临时端口</li>
</ul>
</li>
</ul>
<h2 id="相关命令"><a href="#相关命令" class="headerlink" title="相关命令"></a>相关命令</h2><h3 id="查看对方端口是否开启"><a href="#查看对方端口是否开启" class="headerlink" title="查看对方端口是否开启"></a>查看对方端口是否开启</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">telnet 8.130.85.76 6379</span><br><span class="line"></span><br><span class="line">nc -v 8.130.85.76 6379</span><br></pre></td></tr></table></figure>

<h3 id="查看端口被什么进程监听占用"><a href="#查看端口被什么进程监听占用" class="headerlink" title="查看端口被什么进程监听占用"></a>查看端口被什么进程监听占用</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">netstat -ltpn | grep :22</span><br><span class="line">lsof -n -P -i:22</span><br><span class="line">ss -lntp | grep 22</span><br></pre></td></tr></table></figure>

<h3 id="查看进程监听的端口号"><a href="#查看进程监听的端口号" class="headerlink" title="查看进程监听的端口号"></a>查看进程监听的端口号</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">netstat -ltpn | grep 10920</span><br><span class="line">lsof -n -P -p 10920 | grep TCP</span><br><span class="line">ss -lntp | grep 10920</span><br></pre></td></tr></table></figure>

<h3 id="利用-x2F-proc-x2F-pid打开文件列表"><a href="#利用-x2F-proc-x2F-pid打开文件列表" class="headerlink" title="利用&#x2F;proc&#x2F;pid打开文件列表"></a>利用&#x2F;proc&#x2F;pid打开文件列表</h3> <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ls -l /proc/`pid`/fd</span><br><span class="line">=&gt; 获取socket_inode</span><br><span class="line">cat /proc/net/tcp | grep socket_inode</span><br></pre></td></tr></table></figure>

<h2 id="利用端口进行网络攻击"><a href="#利用端口进行网络攻击" class="headerlink" title="利用端口进行网络攻击"></a>利用端口进行网络攻击</h2><p>redis 6379</p>
<p>利用前提：</p>
<ul>
<li>redis 绑定 0.0.0.0 允许所有来源的 TCP 链接</li>
<li>redis 没有设置密码或密码过于简单</li>
<li>redis-server 进程使用 root 用户启动</li>
<li>没有禁用 save、config、flushall这些高危操作</li>
</ul>
<h2 id="如果临时端口号分配完会发生什么"><a href="#如果临时端口号分配完会发生什么" class="headerlink" title="如果临时端口号分配完会发生什么"></a>如果临时端口号分配完会发生什么</h2><p>如果段时间内产生大量 connect，导致临时端口号被全部分配完，会出现无法建立新的网络连接的情况</p>
<h2 id="临时端口号如何分配"><a href="#临时端口号如何分配" class="headerlink" title="临时端口号如何分配"></a>临时端口号如何分配</h2><p>TCP 四元组</p>
<p>源IP 源端口 目标IP 目标端口</p>
<h3 id="需要分配端口的情况"><a href="#需要分配端口的情况" class="headerlink" title="需要分配端口的情况"></a>需要分配端口的情况</h3><ul>
<li>调用 bind，指定的端口号为 0<ul>
<li>在四元组中，当前只有源 IP 是清楚的</li>
</ul>
</li>
<li>没有调用 bind，直接调用 connect</li>
</ul>
<h3 id="TCP-协议栈用全局的3个哈希表-inet-hash-tables"><a href="#TCP-协议栈用全局的3个哈希表-inet-hash-tables" class="headerlink" title="TCP 协议栈用全局的3个哈希表 inet_hash_tables"></a>TCP 协议栈用全局的3个哈希表 inet_hash_tables</h3><ul>
<li><p>ehash：负责有名有姓的 socket，也就是四元组明确的 socket，key 是源地址、源端口、目标地址、目标端口组成的</p>
<p><code>struct &#123; src_ip,src_port,dst_ip,dst_port &#125;</code></p>
</li>
<li><p>bhash：负责端口分配，key 是端口号，value是使用此端口的所有 socket，一个 socket 可同时在 ehash 和 bhash 中</p>
</li>
<li><p>listening_hash：负责 listen socket</p>
</li>
</ul>
<h4 id="数组-链表实现哈希结构"><a href="#数组-链表实现哈希结构" class="headerlink" title="数组+链表实现哈希结构"></a>数组+链表实现哈希结构</h4><p><code>inet_bhash_bucket</code> 其实是一个数组，数组的每一个元素都是一个 <code>inet_bind_hashbucket</code> 指针，<code>chain</code> 字段是一个链表</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> <span class="title class_">inet_bind_hashbucket</span> &#123;</span><br><span class="line">    <span class="type">spinlock_t</span> lock;</span><br><span class="line">    <span class="keyword">struct</span> <span class="title class_">hlist_head</span> chian;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h3 id="高版本内核临时端口分配策略"><a href="#高版本内核临时端口分配策略" class="headerlink" title="高版本内核临时端口分配策略"></a>高版本内核临时端口分配策略</h3><blockquote>
<p>  协议栈源端口选择性能衰减问题</p>
</blockquote>
<p><code>/proc/sys/net/ipv4/ip_local_port_range</code> 文件指定了临时端口的下界 low 和上界 high，默认情况下，low 是偶数</p>
<ul>
<li>优先给 bind(0) 分配随机的与 low 奇偶性不同的端口，也就是奇数端口。如果奇数端口分配完了，才会尝试分配偶数端口</li>
<li>优先给 connect 分配与 low 奇偶性相同的临时端口，也就是偶数端口。如果偶数端口分配完了，才尝试分配奇数端口</li>
</ul>
<h3 id="性能衰减总结"><a href="#性能衰减总结" class="headerlink" title="性能衰减总结"></a>性能衰减总结</h3><p>端口是有限资源，在高并发情况下，可能出现大量端口号被占用的情况，此时再进行分配端口号需要花费更多时间来寻找空闲端口，增加连接建立的延迟</p>
<h1 id="协议栈测试-packetdrill"><a href="#协议栈测试-packetdrill" class="headerlink" title="协议栈测试 - packetdrill"></a>协议栈测试 - packetdrill</h1><p>packetdrill 脚本采用 c 语言和 tcpdump 混合的语法，脚本文件名一般以 <code>.pkt</code> 为后缀，执行脚本的方式为 <code>sudo ./packetdrill test.pkt</code></p>
<h2 id="脚本格式-时间"><a href="#脚本格式-时间" class="headerlink" title="脚本格式-时间"></a>脚本格式-时间</h2><p>脚本的每一行都有一个时间参数用来表明执行的时间或者预期事件发生的时间，packetdrill 支持绝对时间和相对时间。<code>...</code> 表示使用默认参数信息</p>
<p>绝对时间就是一个简单的数字，相对时间会在数字前面添加一个 +</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 300ms 时执行 accept 调用</span></span><br><span class="line"><span class="number">0.300</span> 	<span class="built_in">accept</span>(<span class="number">3</span>, ..., ...) = <span class="number">4</span></span><br><span class="line"><span class="comment">// 在上一行语句执行结束 10ms 以后再执行</span></span><br><span class="line">+<span class="number">0.010</span> 	<span class="built_in">write</span>(<span class="number">4</span>, ..., <span class="number">1000</span>) = <span class="number">1000</span></span><br></pre></td></tr></table></figure>

<h2 id="逐行解析"><a href="#逐行解析" class="headerlink" title="逐行解析"></a>逐行解析</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">0</span>	<span class="built_in">socket</span>(..., SOCK_STREAM, IPPROTO_TCP) = <span class="number">3</span></span><br><span class="line">+<span class="number">0</span>	<span class="built_in">setsockopt</span>(<span class="number">3</span>, SOL_SOCKET, SO_REUSEADDR, [<span class="number">1</span>], <span class="number">4</span>) = <span class="number">0</span></span><br><span class="line">+<span class="number">0</span>	<span class="built_in">bind</span>(<span class="number">3</span>, ..., ...) = <span class="number">0</span></span><br><span class="line">+<span class="number">0</span>	<span class="built_in">listen</span>(<span class="number">3</span>, <span class="number">1</span>) = <span class="number">0</span></span><br></pre></td></tr></table></figure>

<h3 id="第1行"><a href="#第1行" class="headerlink" title="第1行"></a>第1行</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">0	socket(..., SOCK_STREAM, IPPROTO_TCP) = 3</span><br></pre></td></tr></table></figure>

<p>脚本返回新建的 socket 文件句柄，这里使用 &#x3D; 断言会返回 3。</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240305193213278.png" alt="image-20240305193213278"></p>
<blockquote>
<p>  在Linux系统中，当创建一个新进程时，通常会默认打开三个文件描述符(File Desc, FD)，它们是进程与其执行环境之间通信的基本方式。除此之外，进程可以根据需求打开其他文件、网络连接、管道等，每打开一个新的资源都会分配一个新的文件描述符</p>
<ul>
<li><strong>0 - 标准输入</strong>，stdin，用于从外部获取输入</li>
<li><strong>1 - 标准输出</strong>，stdout，用于输出数据</li>
<li><strong>2 - 标准错误</strong>，stderr，用于输入错误信息或日志，与标准输出独立，允许错误信息和正常输出信息分开处理</li>
</ul>
<p>  文件描述符的作用：文件描述符是一个非负整数，用于代表进程中打开的一个文件或者其他 I&#x2F;O 资源；操作系统使用文件描述符来跟踪每个进程打开的所有文件和资源</p>
</blockquote>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">socket</span><span class="params">(<span class="type">int</span> domain, <span class="type">int</span> type, <span class="type">int</span> protocol)</span></span>;</span><br><span class="line"><span class="comment">// 成功时返回文件描述符，失败时返回 -1</span></span><br><span class="line"><span class="type">int</span> socket_fd = <span class="built_in">socket</span>(AF_INET, SOCK_ATREAM, <span class="number">0</span>);</span><br></pre></td></tr></table></figure>

<ul>
<li><code>domain</code>：表示套接字使用的协议族信息，IPv4、IPv6等；<code>AF_INET</code> 表示 IPv4协议族，<code>AF_INET6</code> 表示 IPv6协议族。绝大多数使用场景下都是使用 <code>AF_INET</code>，即 IPv4协议族</li>
<li><code>type</code>：表示套接字数据传输类型信息，主要分为两种：面向连接的套接字 <code>SOCK_STREAM</code> 和面向无连接报文的套接字 <code>SOCK_DGRAM</code> .<code>SOCK_STREAM</code> 默认协议是 TCP；<code>SOCK_DGRAM</code> 默认协议是 UDP</li>
<li><code>protocol</code>：表示为特定的协议族和套接字类型选择协议</li>
</ul>
<h3 id="第2行"><a href="#第2行" class="headerlink" title="第2行"></a>第2行</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">+<span class="number">0</span>	<span class="built_in">setsockopt</span>(<span class="number">3</span>, SOL_SOCKET, SO_REUSEADDR, [<span class="number">1</span>], <span class="number">4</span>) = <span class="number">0</span></span><br></pre></td></tr></table></figure>

<p>断言返回 0(成功)，非0(失败)</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">setsockopt</span><span class="params">(<span class="type">int</span> sockfd, <span class="type">int</span> level, <span class="type">int</span> optname, <span class="type">const</span> <span class="type">void</span> *optval, <span class="type">socklen_t</span> optlen)</span></span>;</span><br><span class="line"><span class="type">int</span> optval = <span class="number">1</span>;</span><br><span class="line"><span class="built_in">setsockopt</span>(fd, SO_SOCKET, SO_REUSEADDR, &amp;optval, <span class="built_in">sizeof</span>(optval));</span><br></pre></td></tr></table></figure>

<h3 id="第3行"><a href="#第3行" class="headerlink" title="第3行"></a>第3行</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">+<span class="number">0</span>	<span class="built_in">bind</span>(<span class="number">3</span>, ..., ...) = <span class="number">0</span></span><br></pre></td></tr></table></figure>

<p>断言返回 0(成功)，非0(失败)</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">bind</span><span class="params">(<span class="type">int</span> sockfd, <span class="type">const</span> <span class="keyword">struct</span> sockaddr *addr, socklen_k addrlen)</span></span>;</span><br></pre></td></tr></table></figure>

<h3 id="第4行"><a href="#第4行" class="headerlink" title="第4行"></a>第4行</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">+<span class="number">0</span>	<span class="built_in">listen</span>(<span class="number">3</span>, <span class="number">1</span>) = <span class="number">0</span></span><br></pre></td></tr></table></figure>

<p>断言返回 0(成功)，非0(失败)</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">listen</span><span class="params">(<span class="type">int</span> sockfd <span class="type">int</span> backlog)</span></span>;</span><br></pre></td></tr></table></figure>

<h3 id="三次握手"><a href="#三次握手" class="headerlink" title="三次握手"></a>三次握手</h3><p>类 tcpdump 的语法</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">+0	&lt; S 0:0(0) win 4000 &lt;mss 1000&gt;</span><br><span class="line">+0	&gt; S. 0:0(0) ack 1 &lt;...&gt;</span><br><span class="line">+.1	&lt; . 1:1(0) ack 1 win 1000</span><br></pre></td></tr></table></figure>

<p><code>+0	&lt; S 0:0(0) win 4000 &lt;mss 1000&gt;</code></p>
<p><code>&lt;</code> 表示输入的数据包 (input packets)，packetdrill 会构造一个真实的数据包，注入到内核协议栈</p>
<p><code>+0	&gt; S. 0:0(0) ack 1 &lt;...&gt;</code></p>
<p>断言协议栈会立刻回复 SYN+ACK 包，因为还没有发送数据，所以包的 seq 开始值、结束值、长度都为 0，ack 为上次 seq + 1，表示第一个 SYN 包已收到</p>
<p><code>&gt;</code> 表示预期协议栈会响应的包 (outbound packets)，这个包不是由 packetdrill 构造的，是由协议栈发出的，packetdrill 会检测协议栈是否真的发出了一个包，如果没有，则脚本报错停止执行。</p>
<p><code>+.1	&lt; . 1:1(0) ack 1 win 1000</code></p>
<p>三次握手第三步，客户端回复 ACK</p>
<p>0.1s 以后注入一个 ack 包到协议栈，没有携带数据，包的长度为 0，至此三次握手完成</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">+0	&gt; P. 1:11(10) ack 1</span><br></pre></td></tr></table></figure>

<p>断言服务器回复 PUSH+ACK，协议栈立刻发出这 10 个字节数据包，同时把 PSH 标记置为 1.这个包的起始 seq 为 1，结束 seq 为10，长度为 10</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">+.1 &lt; . 1:1(0) ack 11 win 1000</span><br></pre></td></tr></table></figure>

<p>模拟客户端的回复 ACK，100ms 后注入 ack 包，模拟协议栈收到 ack 包</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240305201014024.png" alt="image-20240305201014024"></p>
<h2 id="packetdrill-原理"><a href="#packetdrill-原理" class="headerlink" title="packetdrill 原理"></a>packetdrill 原理</h2><h3 id="packetdrill-语法解析"><a href="#packetdrill-语法解析" class="headerlink" title="packetdrill 语法解析"></a>packetdrill 语法解析</h3><p>pkt &#x3D; c + tcpdump</p>
<blockquote>
<p>  Flex + Bison</p>
</blockquote>
<p>Flex 和 Bison 是 Linux 下用来生成词法分析器和语法分析器两个程序的工具，可以处理结构化输入</p>
<p>Flex 文件定义 pattern，通过 flex 处理 (词法分析) 将输出切分成一段一段的 token，从而执行不同的 action。flex 生成的 tokens 可以交给 Bison 处理，使用 Bison可以更方便的处理负责的逻辑，编写简单、调试方便</p>
<h3 id="TUN-x2F-TAP-设备"><a href="#TUN-x2F-TAP-设备" class="headerlink" title="TUN&#x2F;TAP 设备"></a>TUN&#x2F;TAP 设备</h3><p>tun&#x2F;tap 设备的用处是将协议栈中的部分数据包转发给用户空间的应用程序，给用户空间的程序一个处理数据包的机会</p>
<p>比较常用的数据压缩、加密等功能，就可以在应用程序B里面做进行，tun&#x2F;tap 设备最常用的场景的 VPN</p>
<h3 id="tun-x2F-tap设备与物理网卡的区别"><a href="#tun-x2F-tap设备与物理网卡的区别" class="headerlink" title="tun&#x2F;tap设备与物理网卡的区别"></a>tun&#x2F;tap设备与物理网卡的区别</h3><ul>
<li>对于硬件网络而言，一端连接的是物理网络，一端连接的是网络协议栈</li>
<li>对于 tun&#x2F;tap 设备而言，一端连接的是应用程序，一端连接的是网络协议栈 [通过字符设备文件 &#x2F;net&#x2F;dev&#x2F;tun ]</li>
</ul>
<h1 id="三次握手-1"><a href="#三次握手-1" class="headerlink" title="三次握手"></a>三次握手</h1><h2 id="第一步：客户端发送-SYN"><a href="#第一步：客户端发送-SYN" class="headerlink" title="第一步：客户端发送 SYN"></a>第一步：客户端发送 SYN</h2><p>SYN 不携带数据，但是它占用一个序号，下次发送数据序列号要加1</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306093614528.png" alt="image-20240306093614528"></p>
<h3 id="为什么-SYN-段不携带数据却要消耗一个序列号"><a href="#为什么-SYN-段不携带数据却要消耗一个序列号" class="headerlink" title="为什么 SYN 段不携带数据却要消耗一个序列号"></a>为什么 SYN 段不携带数据却要消耗一个序列号</h3><ul>
<li>不占用序列号的段是不需要确认的，比如纯 ACK 包</li>
<li>SYN 段需要对方的确认，需要占用一个序列号</li>
<li>凡是消耗序列号的 TCP 报文段，一定需要对端确认，如果这个段没有收到确认，会一直重传直到到达指定的次数为止</li>
</ul>
<h2 id="第二步：服务端回复-SYN-ACK"><a href="#第二步：服务端回复-SYN-ACK" class="headerlink" title="第二步：服务端回复 SYN+ACK"></a>第二步：服务端回复 SYN+ACK</h2><ul>
<li>服务端收到客户端的 SYN 段之后，将 SYN 和 ACK 标记都置位</li>
<li>‘序列号’ 存放服务端自己的序列号</li>
<li>‘确认号’ 字段指定对端 (客户端) <strong>下次</strong>发送段的序号，等于 客户端 ISN + 1</li>
</ul>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306093955255.png" alt="image-20240306093955255"></p>
<h2 id="第三步：客户端回复-ACK"><a href="#第三步：客户端回复-ACK" class="headerlink" title="第三步：客户端回复 ACK"></a>第三步：客户端回复 ACK</h2><p>这个 ack 段用于确认收到了服务器发送的 SYN</p>
<h2 id="三次握手还交换了什么"><a href="#三次握手还交换了什么" class="headerlink" title="三次握手还交换了什么"></a>三次握手还交换了什么</h2><p>最大段大小(MSS)、窗口大小、窗口缩放因子、是否支持选择协议</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306094449298.png" alt="image-20240306094449298"></p>
<h2 id="初始-ISN-生成算法"><a href="#初始-ISN-生成算法" class="headerlink" title="初始 ISN 生成算法"></a>初始 ISN 生成算法</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">__u32 <span class="title">secure_tcp_sequence_number</span><span class="params">(__be32 saddr, __be32 daddr, __be <span class="number">16</span> sport, __be16 dport)</span> </span>&#123;</span><br><span class="line">    u32 hash[MD5_DIGEST_WORDS];</span><br><span class="line">    </span><br><span class="line">    <span class="built_in">net_secret_init</span>();</span><br><span class="line">    hash[<span class="number">0</span>] = (__force u32)saddr;</span><br><span class="line">    hash[<span class="number">1</span>] = (__force u32)daddr;</span><br><span class="line">    hash[<span class="number">2</span>] = ((__force u16)sport &lt;&lt; <span class="number">16</span>) + (__force u16)dport;</span><br><span class="line">    hash[<span class="number">3</span>] = net_secret[<span class="number">15</span>];</span><br><span class="line">    <span class="comment">// net_secret 在主机启动时随机生成，在不同主机上不同</span></span><br><span class="line">    <span class="built_in">md5_transform</span>(hash, net_secret);</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">static</span> u32 <span class="title">seq_scale</span><span class="params">(u32 seq)</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 操作系统时间不同，同一台主机上 seq 不同</span></span><br><span class="line">    <span class="keyword">return</span> seq + (<span class="built_in">ktime_to_ns</span>(<span class="built_in">ktime_get_ns</span>()) &gt;&gt; <span class="number">6</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="ISN-设置为固定值产生的问题"><a href="#ISN-设置为固定值产生的问题" class="headerlink" title="ISN 设置为固定值产生的问题"></a>ISN 设置为固定值产生的问题</h2><ul>
<li>不安全性，序列号可被预测攻击</li>
<li>连接复用，导致不同的连接使用相同的初始序列号</li>
</ul>
<h2 id="三次握手中的状态变迁"><a href="#三次握手中的状态变迁" class="headerlink" title="三次握手中的状态变迁"></a>三次握手中的状态变迁</h2><p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306095859184.png" alt="image-20240306095859184"></p>
<h3 id="如果客户端发送-SYN-包，服务端没有回复-ACK"><a href="#如果客户端发送-SYN-包，服务端没有回复-ACK" class="headerlink" title="如果客户端发送 SYN 包，服务端没有回复 ACK"></a>如果客户端发送 SYN 包，服务端没有回复 ACK</h3><p>客户端会进行 SYN 包重传，重传次数由服务器内核参数决定，并且以指数级递增</p>
<p>63s &#x3D; 1s + 2s + 4s + 8s + 16s + 32s </p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># sysctl -a | grep tcp_syn_retries</span><br><span class="line">net.ipv4.tcp_syn_retries = 6</span><br></pre></td></tr></table></figure>

<h2 id="两端同时发起连接建立"><a href="#两端同时发起连接建立" class="headerlink" title="两端同时发起连接建立"></a>两端同时发起连接建立</h2><p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306101431639.png" alt="image-20240306101431639"></p>
<h2 id="TCP-自连接"><a href="#TCP-自连接" class="headerlink" title="TCP 自连接"></a>TCP 自连接</h2><p>源端口与目标端口都是自己</p>
<p>解决自连接</p>
<ul>
<li>让服务监听的端口与客户端随机分配的端口不可能相同</li>
<li>当出现自连接时，主动关闭</li>
</ul>
<h1 id="四次挥手"><a href="#四次挥手" class="headerlink" title="四次挥手"></a>四次挥手</h1><p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306103009702.png" alt="image-20240306103009702"></p>
<h2 id="第一步"><a href="#第一步" class="headerlink" title="第一步"></a>第一步</h2><p>客户端调用 close 方法，执行主动关闭，会发送一个 FIN 报文给服务端，从这以后客户端不能在发送数据给服务端，客户端进行 FIN-WAIT-1 状态。FIN 报文就行将 FIN 标志位设置为 1</p>
<ul>
<li>FIN 段是可以携带数据的，比如可以在它最后要发送的数据块中 <strong>捎带</strong> FIN 段。</li>
<li>不管 FIN 是否携带数据，都需要消耗一个序列号。</li>
<li>一方发送 FIN 包以后不能再发数据给对方，但是还可以接受对方端发送的数据</li>
</ul>
<blockquote>
<p>  FIN-WAIT-1 等待服务端的 ACK 包</p>
</blockquote>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306103230993.png" alt="image-20240306103230993"></p>
<h3 id="什么情况下触发-FIN-报文"><a href="#什么情况下触发-FIN-报文" class="headerlink" title="什么情况下触发 FIN 报文"></a>什么情况下触发 FIN 报文</h3><ul>
<li>程序调用 close</li>
<li>程序异常退出 (内核帮忙善后)</li>
</ul>
<h2 id="第二步"><a href="#第二步" class="headerlink" title="第二步"></a>第二步</h2><p>服务端收到 FIN 包以后，回复确认 ACK 报文，服务端进入 CLOSE-WAIT 状态，客户端收到 ACK 后进入 FIN-WAIT-2状态</p>
<blockquote>
<p>  FIN-WAIT-2 等待服务端的 FIN 包</p>
</blockquote>
<h2 id="第三步"><a href="#第三步" class="headerlink" title="第三步"></a>第三步</h2><p>服务端也没有数据要发送了，发送 FIN 报文给客户端，然后进入 LAST-ACK 状态，等待客户端的 ACK。同前面一样，如果 FIN 段没有携带数据，也需要消耗一个序列号</p>
<h2 id="第四步"><a href="#第四步" class="headerlink" title="第四步"></a>第四步</h2><p>客户端收到服务端的 FIN 报文后，回复 ACK 报文来确认第三步中的 FIN 报文，进入 TIME-WAIT 状态，等待2个 MSL 以后进入 CLOSED 状态；服务端收到 ACK 以后进入 CLOSED 状态</p>
<h2 id="为什么-FIN-报文要消耗一个序列号"><a href="#为什么-FIN-报文要消耗一个序列号" class="headerlink" title="为什么 FIN 报文要消耗一个序列号"></a>为什么 FIN 报文要消耗一个序列号</h2><p>因为 FIN 包需要等待对端 ACK 的确认</p>
<h2 id="为什么挥手要四次，变成三次可以吗"><a href="#为什么挥手要四次，变成三次可以吗" class="headerlink" title="为什么挥手要四次，变成三次可以吗"></a>为什么挥手要四次，变成三次可以吗</h2><p>可以，因为有<strong>延迟确认</strong>的存在，把第二步的 ACK 经常会跟随第三步的 FIN 包一起捎带传送到对端。</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306105532096.png" alt="image-20240306105532096"></p>
<h2 id="同时关闭"><a href="#同时关闭" class="headerlink" title="同时关闭"></a>同时关闭</h2><p>TCP 是双工的，可以两端同时发起 FIN 包</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306111115187.png" alt="image-20240306111115187"></p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306111508563.png" alt="image-20240306111508563"></p>
<h1 id="TCP-11种状态变迁"><a href="#TCP-11种状态变迁" class="headerlink" title="TCP 11种状态变迁"></a>TCP 11种状态变迁</h1><p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306140703841.png" alt="image-20240306140703841"></p>
<h2 id="CLOSED"><a href="#CLOSED" class="headerlink" title="CLOSED"></a>CLOSED</h2><p>这个状态是一个<strong>假想</strong>的状态，是 TCP 连接还未开始建立或者连接已经彻底释放的状态，因此 CLOSED 状态也无法通过 netstat 或者 ss 等工具看到。</p>
<p>从 CLOSED 状态转换为其他状态有两种可能：主动打开 (Active Open) 和被动打开 (Passive Open)</p>
<ul>
<li>被动打开：一般来说，服务器端会监听一个特定的端口，等待客户端的新连接，同时会进入 LISTEN 状态，这种被称为被动打开</li>
<li>主动打开：客户端主动发送一个 SYN 包准备三次握手，被称为主动打开</li>
</ul>
<h2 id="LISTEN"><a href="#LISTEN" class="headerlink" title="LISTEN"></a>LISTEN</h2><p>一端 (通常是服务端)调用 bind、linsten 系统调用监听特定端口时，进入到 LISTEN 状态，等待客户端发送 SYN 报文，三次握手建立连接</p>
<h2 id="SYN-SENT"><a href="#SYN-SENT" class="headerlink" title="SYN-SENT"></a>SYN-SENT</h2><p>客户端发送 SYN 报文，等待 ACK 的过程进入 SYN-SENT状态，同时会开启一个定时器，如果超时还没有收到 ACK 会重发 SYN</p>
<h2 id="SYN-RCVD"><a href="#SYN-RCVD" class="headerlink" title="SYN-RCVD"></a>SYN-RCVD</h2><p>服务端收到 SYN 报文以后，会回复 SYN+ACK，然后等待对端 ACK 的时候进入 SYN-RCVD</p>
<h2 id="ESTABLISHED"><a href="#ESTABLISHED" class="headerlink" title="ESTABLISHED"></a>ESTABLISHED</h2><p>SYN-SENT 或者 SYN-RCVD 状态的连接收到对端确认 ACK 以后进入 ESTABLISHED 状态，连接建立成功</p>
<p>ESTABLISHED 状态的连接有两种可能的状态转换方式</p>
<ul>
<li>调用 close 等系统调用主动关闭连接，这个时候会发送 FIN 包给对端，同时自己进入 FIN-WAIT-1 状态</li>
<li>收到对端的 FIN 包，执行被动关闭，收到 FIN 包后回复 ACK，同时自己进入 CLOSE_WAIT状态</li>
</ul>
<h2 id="FIN-WAIT-1"><a href="#FIN-WAIT-1" class="headerlink" title="FIN-WAIT-1"></a>FIN-WAIT-1</h2><p>主动关闭的一方发送了 FIN 包，等待对端回复 ACK 时，进入 FIN-WAIT-1 状态</p>
<p>FIN-WAIT-1状态的切换</p>
<ul>
<li>收到 ACK：进入 FIN-WAIT-2 状态，等待对端的 FIN 包</li>
<li>收到 FIN：回复对端 ACK，进入 CLOSING 状态 (常出现在<strong>同时关闭</strong>的场景中)</li>
<li>收到 FIN+ACK：回复对端 ACK，进入 TIME_WAIT 状态，跳过了 FIN-WAIT-2 状态</li>
</ul>
<h2 id="FIN-WAIT-2"><a href="#FIN-WAIT-2" class="headerlink" title="FIN-WAIT-2"></a>FIN-WAIT-2</h2><p>处于 FIN-WAIT-2 状态的连接收到 ACK确认包后，进入 FIN-WAIT-2 状态，这个时候主动关闭方的 FIN 包已经被对方确认，等待被动关闭方发送 FIN 包</p>
<h2 id="CLOSE-WAIT-被动关闭方"><a href="#CLOSE-WAIT-被动关闭方" class="headerlink" title="CLOSE-WAIT(被动关闭方)"></a>CLOSE-WAIT(被动关闭方)</h2><p>当有一方想关闭连接的时候，调用 close 等系统调用关闭 TCP 连接会发送 FIN 包给对端，此时被动关闭方收到 FIN 包后进入 CLOSE-WAIT 状态</p>
<h2 id="TIME-WAIT-主动关闭方"><a href="#TIME-WAIT-主动关闭方" class="headerlink" title="TIME-WAIT(主动关闭方)"></a>TIME-WAIT(主动关闭方)</h2><p>TIME-WAIT 可能是所有状态中面试问的最频繁的一种模式，这个状态是收到了被动关闭方的 FIN 包，发送确认 ACK 给对端，开启 2MSL 定时器，定时器到期进入到 CLOSED 状态，连接释放</p>
<h2 id="LAST-ACK-被动关闭方"><a href="#LAST-ACK-被动关闭方" class="headerlink" title="LAST-ACK(被动关闭方)"></a>LAST-ACK(被动关闭方)</h2><p>LAST-ACK 顾名思义就是等待最后的 ACK，被动关闭的一方发送 FIN 包给对端等待 ACK 确认时的状态</p>
<h2 id="CLOSING"><a href="#CLOSING" class="headerlink" title="CLOSING"></a>CLOSING</h2><p>CLOSING 状态比较多在 <strong>同时关闭</strong>，的情况出现，此处的同时关闭，并不是时间意义上的同时，而是指在发送 FIN 包还未收到确认之前，收到了对端的 FIN 的情况</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306143414443.png" alt="image-20240306143414443"></p>
<h1 id="三次握手的秘密"><a href="#三次握手的秘密" class="headerlink" title="三次握手的秘密"></a>三次握手的秘密</h1><blockquote>
<p>  全连接队列、半连接队列</p>
</blockquote>
<h2 id="backlog、半连接队列、全连接队列"><a href="#backlog、半连接队列、全连接队列" class="headerlink" title="backlog、半连接队列、全连接队列"></a>backlog、半连接队列、全连接队列</h2><p>listen函数的定义</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">listen</span><span class="params">(<span class="type">int</span> sockfd, <span class="type">int</span> backlog)</span></span>;</span><br></pre></td></tr></table></figure>

<p><code>backlog</code> 参数定义了系统中可以排队等待服务的客户端连接数量上限</p>
<ul>
<li>半连接队列 (Incomplete connection queue)，又称 SYN 队列</li>
<li>全连接队列 (Completed connection queue)，又称 Accept队列</li>
</ul>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306145341341.png" alt="image-20240306145341341"></p>
<h3 id="半连接队列-QYN-Queue"><a href="#半连接队列-QYN-Queue" class="headerlink" title="半连接队列 (QYN Queue)"></a>半连接队列 (QYN Queue)</h3><p>当客户端发起 SYN 到服务端，服务端收到以后回复 ACK 和自己的 SYN，此时服务端的 TCP 状态从 listen 转变为 SYN_RCVD，此时会将这个连接信息放入半连接队列，半连接队列也被称为 SYN Queue，存储的是 ”Inbound SYN packets“</p>
<p>somaxconn、max_syn_backlog、backlog 三者之间不同组合的最大半连接队列大小值，取三者最小值的向上对2取整</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306150834914.png" alt="image-20240306150834914"></p>
<p>如果用户传入的 backlog值大于系统变量 net.core.somaxconn值，用户设置的 backlog不会生效，使用系统默认值 128</p>
<ul>
<li>在系统参数不修改的情况下，盲目调大 listen 的 backlog 对最终半连接队列的大小不会有影响</li>
<li>在 listen 的backlog 不变的情况下，盲目调大 somaxconn 和 max_syn_backlog 对最终半连接队列的大小不会有影响</li>
</ul>
<h3 id="全连接队列-Accept-Queue"><a href="#全连接队列-Accept-Queue" class="headerlink" title="全连接队列 (Accept Queue)"></a>全连接队列 (Accept Queue)</h3><p>全连接队列包含了服务端所有完成了三次握手，但是还未被应用取走的连接队列。此时的 socket 处于 ESTABLISHED 状态，每次应用程序调用 accept() 函数会移除队列头的连接，如果队列为空，accept() 通常会阻塞，全连接队列也被称为 Accept 队列</p>
<p>生产者、消费者模型</p>
<ul>
<li>内核是一个负责三次握手的生产者，握手完的连接会放入一个队列</li>
<li>应用程序是一个消费者，accept 取走队列中的连接进行下一步的处理</li>
</ul>
<p>这种生产者、消费者模式，在生产过快、消费过慢的情况下就会出现队列积压的现象</p>
<p>两个队列都不是无限大小的，listen 函数的第二个参数 backlog 用来设置全连接队列大小，但不一定就会选用这一个 backlog 值，还受限于 somaxconn</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">listen</span><span class="params">(<span class="type">int</span> sockfd, <span class="type">int</span> backlog)</span></span>;</span><br></pre></td></tr></table></figure>

<p>如果全连接队列满，server会舍弃掉 client 发过来的 ACK (Server会认为此时连接还未完全建立)</p>
<p>全连接队列的大小是 listen 传入的 backlog 和 net.core.somaxconn 中的较小值。全连接队列大小判断是否满足的函数如下：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">bool</span> <span class="title">sk_acceptq_is_full</span><span class="params">(<span class="type">const</span> <span class="keyword">struct</span> sock *sk)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> sk-&gt;sk_ack_backlog &gt; sk-&gt;sk_max_ack_backloh;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>只有真正全连接队列大小是 <strong>backlog + 1</strong>，如果指定 backlog 值为1，那么能容纳的连接个数为 2</p>
<h2 id="ss命令"><a href="#ss命令" class="headerlink" title="ss命令"></a>ss命令</h2><p>ss 命令可以查看全链接队列的大小和当前等待 accept 的连接个数，执行 <code>ss -lnt</code> 即可</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306153512482.png" alt="image-20240306153512482"></p>
<p>对于 LISTEN 状态的套接字，Reccv-Q 表示 accept 队列排对的连接个数，Send-Q 表示全连接队列 (Accept 队列)</p>
<h2 id="backlog-的取值"><a href="#backlog-的取值" class="headerlink" title="backlog 的取值"></a>backlog 的取值</h2><ul>
<li>如果接口处理连接的速度要求非常高，或者在做压力测试，有必要调高这个值</li>
<li>如果页面接口本身性能不好，accept 取走已建连的速度较慢，那么把 backlog 设置再大也没有用，只会增加连接失败的可能性</li>
</ul>
<p>典型的 backlog 值</p>
<ul>
<li>nginx、redis 默认的 backlog值等于 511</li>
<li>Linux 默认的 backlog 为 128</li>
<li>Java 默认的 backlog 为 50</li>
</ul>
<h2 id="tcp-abort-on-overflow-参数"><a href="#tcp-abort-on-overflow-参数" class="headerlink" title="tcp_abort_on_overflow 参数"></a>tcp_abort_on_overflow 参数</h2><p>默认情况下，全连接队列满以后，服务端会忽略客户端的 ACK，随后会重传 SYN+ACK，也可以修改这种行为，这个值由 <code>/proc/net/ipv4/tcp_abort_on_overflow</code> 决定</p>
<ul>
<li>0：表示三次握手最后一步全连接队列满以后 server 会丢掉 client发过来的 ACK，服务端随后会进行重传 SYN+ACK</li>
<li>1：表示全连接队列满以后服务端直接发送 RST 给客户端<ul>
<li>但是回给客户端 RST 包会带来另外的问题，客户端不知道服务端响应的 RST 包是因为”端口没有进程监听“，还是”端口有监听只是队列满了“</li>
</ul>
</li>
</ul>
<h1 id="TCP-协议栈的定时器"><a href="#TCP-协议栈的定时器" class="headerlink" title="TCP 协议栈的定时器"></a>TCP 协议栈的定时器</h1><h2 id="连接建立定时器-conection-establishment"><a href="#连接建立定时器-conection-establishment" class="headerlink" title="连接建立定时器 conection establishment"></a>连接建立定时器 conection establishment</h2><p>当发送端发送 SYN 报文想要建立一条新连接时，会开启连接建立定时器，如果没有收到对端的 ACK 包将进行重传</p>
<h2 id="重传定时器-retransmission"><a href="#重传定时器-retransmission" class="headerlink" title="重传定时器 retransmission"></a>重传定时器 retransmission</h2><p>第一个定时器是连接建立没有收到 ACK 的情况，如果在发送数据包时没有收到 ACK 呢？</p>
<p>重传时间间隔是指数级增加，直到 120s 为止，重传次数是 15 次，这个值由 <code>/proc/sys/net/ipv4/tcp_resties2</code> 决定，总时间近 15 分钟</p>
<h2 id="延迟-ACK-定时器"><a href="#延迟-ACK-定时器" class="headerlink" title="延迟 ACK 定时器"></a>延迟 ACK 定时器</h2><p>在 TCP 收到数据包以后在没有数据包要回复时，不马上回复 ACK，这是开启一个定时器，等待一段时间看是否有数据需要回复。如果期间有数据要回复，则在回复的数据中捎带 ACK，如果到了时间也没有数据要发生，则也要发送 ACK。(在Centos7上这个值为 40 ms)</p>
<h2 id="persist-定时器-zero-window"><a href="#persist-定时器-zero-window" class="headerlink" title="persist 定时器 (zero window)"></a>persist 定时器 (zero window)</h2><p>Persist 定时器是专门为<strong>零窗口探测</strong>准备的。TCP 利用滑动窗口来实现流量控制，当接收端 B 接收窗口为 0 时，发送端 A 此时不能再发送数据，发送端此时开启 Persist 定时器，超时后发送一个特殊报文给接收端，看接收端窗口是否已经恢复，这个特殊报文只有一个字节</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306162852295.png" alt="image-20240306162852295"></p>
<h2 id="保活定时器-keepalive-timer"><a href="#保活定时器-keepalive-timer" class="headerlink" title="保活定时器 keepalive timer"></a>保活定时器 keepalive timer</h2><p>如果通信以后一段时间再也没有传输过数据，如何知道对方是否挂掉或者重启呢？</p>
<p>TCP 提出来一个做法，就是在连接空闲时间超过 2 小时，会发送一个探测报文，如果对方有回复则表示连接还存活；如果经过几次探测对方都没有回复，则表示连接已失效，客户端会丢弃这个连接</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306163156003.png" alt="image-20240306163156003"></p>
<h2 id="FIN-WAIT-2-定时器"><a href="#FIN-WAIT-2-定时器" class="headerlink" title="FIN-WAIT-2 定时器"></a>FIN-WAIT-2 定时器</h2><p>四次挥手中，主动关闭的一方收到 ACK 以后从 FIN-WAIT-1 进入 FIN-WAIT-2 状态，等待对端的 FIN 包的到来，FIN-WAIT-2 定时器的作用是防止对方一直不发送 FIN 包，防止自己一直处于等待状态。这个值由 <code>/proc/sys/net/ipv4/tcp_fin_timout</code> 决定，默认值为 60s</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306163525139.png" alt="image-20240306163525139"></p>
<h2 id="TIME-WAIT-定时器"><a href="#TIME-WAIT-定时器" class="headerlink" title="TIME-WAIT 定时器"></a>TIME-WAIT 定时器</h2><p>TIME-WAIT 定时器也称为 2MSL 定时器，主动关闭连接的一方在 TIME-WAIT 持续 2 个 MSL 的时间，超时候端口号可以被安全重用 </p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306163900851.png" alt="image-20240306163900851"></p>
<h1 id="TIME-WAIT-状态"><a href="#TIME-WAIT-状态" class="headerlink" title="TIME-WAIT 状态"></a>TIME-WAIT 状态</h1><p>首先明确一点，<font color=blue>只有主动断开连接的那一方才会进入 <strong>TIME-WAIT</strong> 状态</font>，且会在这个状态保持 2 个 MSL (MAX Segment Lifetime)</p>
<h2 id="MSL-MAX-Segment-Lifetime"><a href="#MSL-MAX-Segment-Lifetime" class="headerlink" title="MSL: MAX Segment Lifetime"></a>MSL: MAX Segment Lifetime</h2><p>MSL (报文最大生存时间) 是 TCP 报文在网络中的最大生存时间，这个值与 IP 报文投的 TTL 字段有密切联系</p>
<p>IP 报文头中有一个 8 位的存活时间字段 (Time to live, TTL)，这个存活时间存储的不是具体的时间，而是一个 IP 报文最大可经过的路由数，每经过一个路由器，TTL 减 1，当 TTL 减到 0 时，这个 IP 报文会被丢弃。</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306165641565.png" alt="image-20240306165641565"></p>
<p>TTL 经过路由器不断减小，假设初始 TTL 为 12，经过下一个路由器 TTL 变为 10，后面每经过一个路由器以后 TTL 减 1</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306165834734.png" alt="image-20240306165834734"></p>
<h2 id="TIME-WAIT-存在的原因"><a href="#TIME-WAIT-存在的原因" class="headerlink" title="TIME-WAIT 存在的原因"></a>TIME-WAIT 存在的原因</h2><ul>
<li>数据报文可能在发送途中延迟但最终会到达，因此要等老的”迷路“的重复报文段在网络中失效，这样可以避免用相关源端口和目标端口创建新连接时收到旧连接姗姗来迟的数据包，造成数据错乱</li>
</ul>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306170251164.png" alt="image-20240306170251164"></p>
<ul>
<li>确保可靠实现 TCP 全双工终止连接，在关闭连接的四次挥手中，最终的 ACK 由主动关闭方发出，如果这个 ACK 丢失，对端将重发 FIN，如果主动关闭方不维持 TIME-WAIT 直接进入 CLOSED 状态，则无法重传 ACK，被动关闭方因此不能及时可靠释放</li>
</ul>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306170654697.png" alt="image-20240306170654697"></p>
<h2 id="为什么时间是两个-MSL"><a href="#为什么时间是两个-MSL" class="headerlink" title="为什么时间是两个 MSL"></a>为什么时间是两个 MSL</h2><ul>
<li>1 个 MSL 确保四次挥手中主动关闭方最后的 ACK 报文最终能达到对端</li>
<li>1 个 MSL 确保对端没有收到 ACK 重传的 FIN 报文可以到达</li>
</ul>
<p>2MSL &#x3D; 去向 ACK 消息最大存活时间(MSL) + 来向 FIN 消息最大存活时间(MSL)</p>
<h2 id="TIME-WAIT-的问题"><a href="#TIME-WAIT-的问题" class="headerlink" title="TIME-WAIT 的问题"></a>TIME-WAIT 的问题</h2><p>在非常繁忙的服务器上，如果有大量的 TIME-WAIT 状态的连接会出现的问题</p>
<ul>
<li>连接表无法复用</li>
<li>socket 结构体内存占用</li>
</ul>
<h3 id="连接表无法复用"><a href="#连接表无法复用" class="headerlink" title="连接表无法复用"></a>连接表无法复用</h3><p>因为处于 TIME-WAIT 的连接会存活 2MSL(60s)，意味着相同的 TCP 连接四元组 (源端口、源 IP、目的端口、目的 IP) 在 1mins 内没有办法复用。</p>
<p>假设主动断开的一方是客户端，对于 web 服务器而言，目标地址、目标端口都是固定值，客户端的 IP 也是固定的，那么能变化的就是端口号，在一台 Linux 机器上，端口最多是 65535。如果客户端与服务器通信全部使用短连接，不停地创建链接，接着关闭连接，客户端会操作大量的 TCP 连接进入 TIME-WAIT 状态</p>
<h3 id="应对-TIME-WAIT的操作"><a href="#应对-TIME-WAIT的操作" class="headerlink" title="应对 TIME-WAIT的操作"></a>应对 TIME-WAIT的操作</h3><p>针对 TIME-WAIT 持续时间过长的问题，Linux 新增了几个相关的选项，<code>net.ipv4.tcp_tw_reuse</code> 和 <code>net.ipv4.tcp_tw_recycle</code> 这两个参数都依赖于 TCP 头部拓展选项：timestamp</p>
<h3 id="TCP-头部时间戳选项-TCP-Timestamps-Option-TSopt"><a href="#TCP-头部时间戳选项-TCP-Timestamps-Option-TSopt" class="headerlink" title="TCP 头部时间戳选项 (TCP Timestamps Option, TSopt)"></a>TCP 头部时间戳选项 (TCP Timestamps Option, TSopt)</h3><p>除了 MSS、Window Scale 还有一个重要的选项：时间戳</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306185218095.png" alt="image-20240306185218095"></p>
<p>时间戳由四部分构成：类别 (kind)、长度 (Length)、发送方时间戳 (TS value)、回显时间戳 (TS Echo Reply)。时间戳选项类别 (kind) 的值等于 8，用来与其他类型的选项区分，长度 (length) 等于 10，两个时间戳相关的选项都是 4字节</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240306185502437.png" alt="image-20240306185502437"></p>
<ul>
<li>时间戳是一个单调递增的值，与我们所知的 epoch 时间戳不是一回事，这个选项不要钱两太主机进行时钟同步</li>
<li>timestamps 是一个双向的选项，如果一方不开启，双方都将停用 timestamps</li>
</ul>
<h3 id="tcp-tw-reuse-选项"><a href="#tcp-tw-reuse-选项" class="headerlink" title="tcp_tw_reuse 选项"></a>tcp_tw_reuse 选项</h3><p>缓解紧张的端口资源，一个可行的方法是重用“浪费”的处于 TIME-WAIT 状态的连接，当开启 <code>net.ipv4.tcp_tw_reuse</code> 选项时，处于 TIME_WAIT 状态的连接可以被重用</p>
<h3 id="tcp-tw-recyle-选项"><a href="#tcp-tw-recyle-选项" class="headerlink" title="tcp_tw_recyle 选项"></a>tcp_tw_recyle 选项</h3><p>tcp_tw_recyle 是一个比 tcp_tw_reuse 更激进的方案，系统会缓存每台主机 (IP) 连接过来的最新的时间戳，对于新来的连接，如果发现 SYN 包中的时间戳与之前记录的来自同一主机的同一连接的分组所携带的时间戳相比更旧，则直接丢弃；如果更新则接受复用 TIME-WAIT 连接</p>
<p>这种机制在客户端与服务端一对一的情况下没有问题，如果经过了 NAT 或者负载均衡，问题就很严重了</p>
<h3 id="NAT"><a href="#NAT" class="headerlink" title="NAT"></a>NAT</h3><p>NAT (Network Address Translator) 的出现是为了缓解 IP 地址耗尽的临时方案，IPv4的地址是 32 位，全部利用最多只能有 42.9 亿个地址，去掉保留地址、组播地址，只剩下 30 多亿</p>
<p>优势</p>
<ul>
<li>出口 IP 共享：通过一个公网地址可以让许多机器连上网络，解决 IP 地址不够用的问题</li>
<li>安全隐私防护：实际的机器可以隐藏自己真实的 IP 地址</li>
</ul>
<p>缺点</p>
<ul>
<li>NAT 会对包进行修改，有些包无法通过 NAT</li>
</ul>
<h3 id="当-tcp-tw-recycle-遇上-NAT"><a href="#当-tcp-tw-recycle-遇上-NAT" class="headerlink" title="当 tcp_tw_recycle 遇上 NAT"></a>当 tcp_tw_recycle 遇上 NAT</h3><p>因为客户端出口 IP 相同，会导致服务端看起来都在与同一个 Host 打交道。不同客户端携带的 timestamp 只跟自己相关，如果一个时间戳较大的客户端 A 通过 NAT 与服务器建连，时间戳较小的客户端 B 通过 NAT 发送的包，服务器认为是过期重复的数据，直接丢弃，导致 B 无法正常建连和发数据</p>
<h3 id="TIME-WAIT-存在的意义"><a href="#TIME-WAIT-存在的意义" class="headerlink" title="TIME-WAIT 存在的意义"></a>TIME-WAIT 存在的意义</h3><ul>
<li>可靠的实现 TCP 全双工的连接终止 (处理最后 ACK 丢失的情况)</li>
<li>避免当前关闭连接与后续连接混淆 (让旧连接的包在网络中消失)</li>
</ul>
<h1 id="SYN-Flood-SYN-泛洪攻击"><a href="#SYN-Flood-SYN-泛洪攻击" class="headerlink" title="SYN Flood (SYN 泛洪攻击)"></a>SYN Flood (SYN 泛洪攻击)</h1><p>SYN Flood 是一种 DoS 攻击，场景：客户端大量伪造 IP 发送 SYN 包，服务端回复的 ACK+SYN 去到了一个未知的 IP 地址，势必会造成服务端大量的连接处于 SYN-RCVD 状态，而服务端的半连接队列大小是有限的，如果半连接队列满，会出现无法处理正常请求的状况</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240307093141148.png" alt="image-20240307093141148"></p>
<h2 id="Scapy-工具"><a href="#Scapy-工具" class="headerlink" title="Scapy 工具"></a>Scapy 工具</h2><p>Scapy 是一个用 Python 编写的交互式数据包处理程序，它可以让用户发送、侦听和解析并伪装网络报文</p>
<blockquote>
<p>  <a target="_blank" rel="noopener" href="https://scapy.net/">https://scapy.net/</a></p>
</blockquote>
<h2 id="scapy-构造数据包的方式"><a href="#scapy-构造数据包的方式" class="headerlink" title="scapy 构造数据包的方式"></a>scapy 构造数据包的方式</h2><p>scapy 采用 &#x2F; 来堆叠多个层的数据</p>
<p>如：IP() &#x2F; TCMP()，如果用 TCP 发送一段字符 hello</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">IP(src=&quot;源IP&quot;, dst=&quot;目的IP&quot;) / TCP(sport=&quot;源端口&quot;, dport=&quot;目的端口&quot;) / &quot;hello&quot;</span><br></pre></td></tr></table></figure>

<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240307103132596.png" alt="image-20240307103132596"></p>
<p>如：发送 DNS 查询</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">IP(dst=&quot;8.8.8.8&quot;) / UDP() / DNS(rd=1, qd=DNSQR(qname=&quot;www.baidu.com&quot;))</span><br></pre></td></tr></table></figure>

<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240307103158805.png" alt="image-20240307103158805"></p>
<h2 id="接收数据"><a href="#接收数据" class="headerlink" title="接收数据"></a>接收数据</h2><p>如果想拿到返回的结果，可以使用sr (send-receive) 函数，sr1函数(只取第一个应答数据包)</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240307103111055.png" alt="image-20240307103111055"></p>
<h2 id="scapy-模拟"><a href="#scapy-模拟" class="headerlink" title="scapy 模拟"></a>scapy 模拟</h2><p>在客户端用 scapy 执行 sr1 函数向目标机器发送 SYN 包</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240307104202076.png" alt="image-20240307104202076"></p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240307104216661.png" alt="image-20240307104216661"></p>
<p>其中服务端收到的 SYN 包的源地址就是 src 中定义的，从而隐藏了自己的 IP，也可以将 src 设置为某一网段，如 <code>66.6.*.*</code></p>
<p>当服务端收到 scapy 模拟的 SYN 包后，马上回复了 SYN+ACK 给这些虚假的 IP 服务器。服务端的 SYN-RECV 的数量偶尔上升又下降，因为对端回复了 RST 包，这条连接在收到 RST 以后就从半连接队列清除了。如果攻击者控制了大量机器，同时发起 SYN，依然会对服务器造成很大的影响</p>
<p>并且，SYN+ACK 去往不知道是哪里的主机，是否回复 RST 完全取决于自己，如果它直接忽略掉 SYN，不回复 RST，服务端会认为是自己的 SYN+ACK 丢失了，会进行重传</p>
<p>通过服务端抓包文件可以看到，服务器因为 SYN+ACK 丢失了，会进行重传，重传次数由 <code>/proc/sys/net/ipv4/tcp_synack_retries</code> 决定。以 tcp_syncak_retries&#x3D;5为例，在重传次数达到上限后 (重传时间仍是指数级退避1s、2s、4s、8s、16s)，发送完最后一次 SYN+ACK 包以后，等待 32s，服务端才会丢掉这个连接，把处于 SYN-RECV 状态的 socket 关闭</p>
<h2 id="危害"><a href="#危害" class="headerlink" title="危害"></a>危害</h2><p>在这种情况下，一次恶意的 SYN 包，会占用一个服务器连接 63s (1+2+4+8+16+32)，如果这个时候有大量的恶意 SYN 包过来连接服务器，很坑半连接队列就会被占满，不能接受正常的用户请求</p>
<h3 id="如何解决-SYN-Flood-攻击"><a href="#如何解决-SYN-Flood-攻击" class="headerlink" title="如何解决 SYN Flood 攻击"></a>如何解决 SYN Flood 攻击</h3><ul>
<li>增大 SYN 连接数：<code>tcp_max_syn_backlog</code> 心理安慰</li>
<li>减少 SYN+ACK 重传次数 <code>tcp_synack_retries</code> 用处不大</li>
<li>启用 <code>tcp_syncookies</code> 诸多局限</li>
</ul>
<h3 id="SYN-Cookie"><a href="#SYN-Cookie" class="headerlink" title="SYN Cookie"></a>SYN Cookie</h3><p>SYN Cookie 技术最早在 1996年提出，用于解决 SYN Flood 攻击</p>
<p>由 <code>/proc/sys/net/ipv4/tcp_syncookies</code> 控制</p>
<ul>
<li>1：表示连接队列满时启用 (默认)</li>
<li>0：表示禁用</li>
<li>2：表示始终启用</li>
</ul>
<h3 id="SYN-Cookie-原理"><a href="#SYN-Cookie-原理" class="headerlink" title="SYN Cookie 原理"></a>SYN Cookie 原理</h3><p>SYN Cookie 的原理是基于无状态机制，服务器收到 SYN 包以后不马上为 Inbound SYN 分配内存资源，而是根据这个 SYN 包计算出一个 Cookie 值，作为握手第二步的序列号回复 SYN+ACK，等对方回应 ACK 包时校验回复的 ACK 值是否合法，如果合法三次握手才成功，分配连接资源</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240307122605379.png" alt="image-20240307122605379"></p>
<h3 id="Cookie-值计算的规则"><a href="#Cookie-值计算的规则" class="headerlink" title="Cookie 值计算的规则"></a>Cookie 值计算的规则</h3><p>Cookie 总长度为 32bit</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> __u32 <span class="title function_">secure_tcp_syn_cookie</span><span class="params">(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, _u32 sseq, _u32 data)</span> &#123;</span><br><span class="line">    <span class="comment">// 系统开机经过的分钟数</span></span><br><span class="line">    u32 count = tcp_cookie_time();</span><br><span class="line">    <span class="keyword">return</span> ()</span><br><span class="line">        <span class="comment">// 第一次 hmac 哈希</span></span><br><span class="line">    	cookie_hash(saddr, daddr, sport, dport, <span class="number">0</span>, <span class="number">0</span>) +</span><br><span class="line">        <span class="comment">// 客户端传过来的 seq 序列号</span></span><br><span class="line">        sseq +</span><br><span class="line">        <span class="comment">// 系统开机经过的分钟数左移 24 位</span></span><br><span class="line">        (count &lt;&lt; COOKIEBITS) +</span><br><span class="line">        <span class="comment">// data 包含了 MSS, 增加 MSS 值做第二次 hmac 哈希然后取低 24 位</span></span><br><span class="line">        ((cookie_hash(saddr, daddr, sport, dport, count, <span class="number">1</span>) + data) &amp; COOKIEMASH));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>其中 COOKIEBITS 等于 24，COOKIEMASK 为低 24 位的掩码，即 0x00FFFFFF，count 为系统的分钟数，sseq 为客户端传递的 seq序列号</p>
<h3 id="SYN-Cookie-的缺陷"><a href="#SYN-Cookie-的缺陷" class="headerlink" title="SYN Cookie 的缺陷"></a>SYN Cookie 的缺陷</h3><p>单纯从 TCP 的角度，无法较好的解决这个问题</p>
<ul>
<li>MSS 值只能是少数的几种，由数组 msstab 确定</li>
<li>因为 syn-cookie 是一个无状态的机制，服务端不保存状态，不能使用其他所有的 TCP 选项，比如 WScale、SACK 这些 (可以通过其他的 hack 方式实现)</li>
</ul>
<h1 id="SOCKET-选项"><a href="#SOCKET-选项" class="headerlink" title="SOCKET 选项"></a>SOCKET 选项</h1><h2 id="SO-REUSEADDR"><a href="#SO-REUSEADDR" class="headerlink" title="SO_REUSEADDR"></a>SO_REUSEADDR</h2><p>服务端主动断开连接以后，需要等 2 个 MSL 以后在最终释放这个连接，重启后要绑定同一个端口，默认情况下，操作系统的实现都会组织新的监听套接字绑定到这个端口上</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240307133217139.png" alt="image-20240307133217139"></p>
<p>TCP 要求这样的四元组必须是唯一的，但大多数操作系统的实现要求更加严格，只要还有连接在使用这个本地端口，则本地端口不能被重用 (bind 调用失败)</p>
<p>启用 SO_REUSEADDR 套接字选项可以解除这个限制，默认情况下这个值为 0，表示关闭。</p>
<p>在 Java 中，reuseAddress 不同的 JVM 有不同的实现，为了保险起见，写 TCP、HTTP 服务一定要主动设置这个参数为 1</p>
<h3 id="为什么通常不会在客户端上出现"><a href="#为什么通常不会在客户端上出现" class="headerlink" title="为什么通常不会在客户端上出现"></a>为什么通常不会在客户端上出现</h3><p>因为客户端都是用的临时端口，这些临时端口与处于 TIME-WAIT 状态的短裤恰好相同的可能性不大，就算相同换一个新的临时端口就好了</p>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>SO_REUSEADDR 是一个 Socket 选项，主要是用来告诉操作系统内核，如果端口已被占用，但是 TCP 连接状态处于 TIME-WAIT (包括FIN-WAIT-1、FIN-WAIT-2)，可以重用端口</p>
<p>所有 TCP 服务端程序，一定要在 bind 之前设置 SO_ESUSEADDR 选项，不然可能会出现无法短时间内重启服务端程序</p>
<h2 id="SO-LINGER"><a href="#SO-LINGER" class="headerlink" title="SO_LINGER"></a>SO_LINGER</h2><p>往套接字写东西，实际上是往内核写东西</p>
<p>关闭套接字的常见方式</p>
<ul>
<li>FIN：优雅关闭，发送 FIN 包表示自己这端所有数据都已经发送出去了，后面不会再发生数据</li>
<li>RST：强制连接重置关闭，无法做出什么保证</li>
</ul>
<p>调用 socket.close() 时会发生什么</p>
<ul>
<li>正常情况<ul>
<li>操作系统等所有的数据发送完才会关闭连接</li>
<li>因为是主动关闭，所以连接将处于 TIME-WAIT 两个 MSL</li>
</ul>
</li>
</ul>
<p>SO_LINGER 参数是一个 linger 结构体</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> <span class="title class_">linger</span> &#123;</span><br><span class="line">    <span class="comment">// 是否启用</span></span><br><span class="line">    <span class="type">int</span> l_onoff;</span><br><span class="line">    <span class="comment">// 等待多久</span></span><br><span class="line">    <span class="type">int</span> l_linger;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li><p>l_onoff：用来表示是否启用 linger 特性，非 0 为启用，0 为禁用，linux 内核默认为禁用，这种情况下 close 函数立即返回，操作系统负责把缓存队列中的数据全部发送至对端</p>
</li>
<li><p>l_linger：在 l_onoff 为非 0 (即启用特性) 时才会生效</p>
<ul>
<li>如果 l_linger 的值为 0，那么调用 close，close 函数会立即丢弃未发送的数据，并发送 RST 包重置连接</li>
<li>如果 l_linger 的值为非 0，那么此时 close 函数在阻塞，直到 l_linger 超时或数据发送完毕，发送队列在超时时间内继续尝试发送，如果发送完毕则正常关闭连接，如果缓冲区中还有时间则丢弃缓冲区内容，并 RST 掉连接</li>
</ul>
</li>
</ul>
<h1 id="滑动窗口-流量控制"><a href="#滑动窗口-流量控制" class="headerlink" title="滑动窗口 - 流量控制"></a>滑动窗口 - 流量控制</h1><p>流量控制：如果接收缓冲区已满，发送端应该停止发送数据</p>
<h2 id="接收窗口-rwnd"><a href="#接收窗口-rwnd" class="headerlink" title="接收窗口 rwnd"></a>接收窗口 rwnd</h2><p>为了控制发送端的速率，接收端会告知客户端自己接收窗口 (Receive Window, rwnd)，也就是接收缓冲区中空余的部分</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240308143514656.png" alt="image-20240308143514656"></p>
<p>TCP 在收到数据包回复的 ACK 包里会带上自己接收窗口的大小，接收端需要根据这个值调整自己的发送策略</p>
<h2 id="发送窗口与接收窗口"><a href="#发送窗口与接收窗口" class="headerlink" title="发送窗口与接收窗口"></a>发送窗口与接收窗口</h2><p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240308143726662.png" alt="image-20240308143726662"></p>
<p>win 表示向对方声明自己的接收<strong>窗口大小</strong>，对方收到以后，会把自己的<strong>发送窗口</strong>限制在 29312 大小以内</p>
<h2 id="TCP-包状态分类"><a href="#TCP-包状态分类" class="headerlink" title="TCP 包状态分类"></a>TCP 包状态分类</h2><p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240308143919994.png" alt="image-20240308143919994"></p>
<ul>
<li><font color=pink>粉色部分</font>：表示已发送且已经收到 ACK 确认的数据包</li>
<li><font color=blue>蓝色部分</font>：表示已发送，但未收到 ACK 的数据包，发送方不确定这部分数据对端有没有收到，在一段时间内没有收到 ACK，发送端需要重传这部分的数据包</li>
<li><font color=gree>绿色部分</font>：表示未发送，但接收端已经准备就绪可以接收的数据包</li>
<li><font color=yellow>黄色部分</font>：表示还未发送，且这部分接收端没有空间接收</li>
</ul>
<h2 id="发送窗口-send-window-与可用窗口-uable-window"><a href="#发送窗口-send-window-与可用窗口-uable-window" class="headerlink" title="发送窗口(send window)与可用窗口(uable window)"></a>发送窗口(send window)与可用窗口(uable window)</h2><p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240308144456850.png" alt="image-20240308144456850"></p>
<ul>
<li>发送窗口是 TCP 滑动窗口的核心概念，它表示了在某个时刻，一端能拥有的最大未确认的数据包大小 (最大在途数据)，发送窗口是发送端被允许发送的最大数据包大小</li>
<li>可用窗口是发送端还能发送的最大数据包大小，它等于发送窗口的大小减去在途数据包的大小</li>
</ul>
<h2 id="TCP-Zero-Window"><a href="#TCP-Zero-Window" class="headerlink" title="TCP Zero Window"></a>TCP Zero Window</h2><p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240308145611008.png" alt="image-20240308145611008"></p>
<p>TCP 包中的 win&#x3D; 表示接收窗口的大小，表示接收端还有多少缓冲区可以接收数据，当窗口变成 0 时，表示接收端暂时不能再接收数据了</p>
<ul>
<li>TCP Window Full 是站在 <strong>发送端</strong> 的角度上，表示在途字节数等于对方接收窗口的情况，此时发送端不能再发数据给对方，直到发送的数据包得到 ACK</li>
<li>TCP Zero Window 是站在 <strong>接收端</strong> 的角度上，是接收端的接收窗口已满，告知对方不能再发送数据给自己</li>
</ul>
<h1 id="Nagle-算法"><a href="#Nagle-算法" class="headerlink" title="Nagle 算法"></a>Nagle 算法</h1><p>Nagle 算法：减少发生端频繁地发送小包给对方</p>
<p>Nagle算法要求：当一个 TCP 连接中有在传数据 (已经发出但还未确认的数据) 时，小于 MSS 的报文段就不能被发送，直到所有的在传数据都收到了 ACK。同时收到 ACK 后， TCP 还不会马上就发送数据，会收集小包合并一起发送</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240308155326870.png" alt="image-20240308155326870"></p>
<h2 id="Nagle-算法的意义"><a href="#Nagle-算法的意义" class="headerlink" title="Nagle 算法的意义"></a>Nagle 算法的意义</h2><p>Nagle 算法的作用是减少小包在客户端和服务器直接传输，一个包的 TCP 头和 IP 头加起来至少有 40 个字节，如果携带数据比较小的话，那就十分的浪费</p>
<h2 id="Nagle-算法的局限性"><a href="#Nagle-算法的局限性" class="headerlink" title="Nagle 算法的局限性"></a>Nagle 算法的局限性</h2><p>Nagle 算法在通信时延较低的场景下意义不大，在 Nagle 算法中 ACK 返回的越快，下一次数据传输就越早</p>
<p>假设 RTT 为 10ms 且没有延迟确认，那么敲击键盘的间隔大于 10ms 的话就不会触发 Nagle 算法，如果想要触发 Nagle 的停等 (stop-wait) 机制，1s 内要输入超过 100 个字符</p>
<p>如果客户端到服务器的 RTT 较大，比如 200ms，那么此时只要 1s 内输入超过 5 个字符，就有可能触发 Nagle 算法</p>
<p>Nagle 算法出的的时间网络带宽很小，当有大量小包传输时，很容易将带宽占满，出现丢包重传等现象。因此对于 ssh 这种交互式的应用场景，选择开启 Nagle 算法可以使得不再那么频繁的发送小包，而是合并到一起，代价是会有一些延迟。现在的 ssh 客户端已经默认关闭的 Nagle 算法</p>
<h2 id="Nagle-总结"><a href="#Nagle-总结" class="headerlink" title="Nagle 总结"></a>Nagle 总结</h2><p>Nagle 算法应用于发送端</p>
<ul>
<li>当第一次发送数据时不用等待，就算是 1byte 的的小包也立即发送</li>
<li>后面发送数据时需要累计数据包直到满足下面的条件之一才会继续发送数据<ul>
<li>数据包达到最大段大小 MSS</li>
<li>接收端收到之前数据包的确认 ACK</li>
</ul>
</li>
</ul>
<h1 id="延迟确认-delayed-ack"><a href="#延迟确认-delayed-ack" class="headerlink" title="延迟确认 - delayed ack"></a>延迟确认 - delayed ack</h1><p>delayed ack 对应接收端而言，减少空包的回复</p>
<p>不是每个数据包都有对应的 ACK 包，接收端收到数据以后也不是必须马上回复 ACK 的</p>
<blockquote>
<p>  delayed ack time &#x3D; 40ms</p>
</blockquote>
<ul>
<li>接收端恰好有数据要回复客户端：ACK 搭上顺风车一块发送</li>
<li>期间又有数据端的数据传输过来：把多吃 ACK 合并为一个立刻发送出去</li>
<li>一段数据没有顺风车：不能让接收端等太久，一个空包也得发送</li>
</ul>
<h1 id="TCP-拥塞控制"><a href="#TCP-拥塞控制" class="headerlink" title="TCP 拥塞控制"></a>TCP 拥塞控制</h1><h2 id="慢启动"><a href="#慢启动" class="headerlink" title="慢启动"></a>慢启动</h2><p>如果有足够的带宽，可以选择用最快的速度传输数据，但是如果是一个缓慢的移动网络呢？如果发送的数据过多，只会造成更大的网络延迟。这是基于整体的考虑，每个 TCP 连接都会有一个拥塞窗口的限制，最初这个值很小，随着时间的推移，每次发送的数据量如果在不丢包的情况下，”慢慢”地递增，这种机制被称为<strong>慢启动</strong></p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240308180659805.png" alt="image-20240308180659805"></p>
<ul>
<li>三次握手以后，双手通过 ACK 告诉对方自己的接收窗口 (rwnd) 的大小，之后就可以互相发送数据了</li>
<li>通信双方各自初始化自己的拥塞窗口 (cwnd) 的大小</li>
<li>cwnd 初始值较小时，每收到一个 ACK，cwnd+1，每经过一个 RTT，cwnd变为之前的两倍</li>
</ul>
<p>慢启动拥塞窗口 (cwnd) 肯定不能无止境的指数级增长下去，否则拥塞控制就变成拥塞失控了，它的阈值称为<strong>慢启动阈值</strong> (Slow Start Threshold，ssthresh)。ssthresh 就是一到刹车，让拥塞窗口别涨那么快</p>
<ul>
<li>当 cwnd &lt; ssthresh，拥塞窗口按指数级增长 (慢启动)</li>
<li>当 cwnd &gt; ssthresh，拥塞窗口按线性增长 (拥塞避免)</li>
</ul>
<h2 id="拥塞避免"><a href="#拥塞避免" class="headerlink" title="拥塞避免"></a>拥塞避免</h2><p>当 cwnd &gt; ssthresh，拥塞窗口进入拥塞避免阶段，在这个阶段，每一个往返 RTT，拥塞窗口大约增加 1 个 MSS 大小，直到检测到拥塞为止 </p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240308181343875.png" alt="image-20240308181343875"></p>
<h3 id="慢启动-vs-拥塞避免"><a href="#慢启动-vs-拥塞避免" class="headerlink" title="慢启动 vs 拥塞避免"></a>慢启动 vs 拥塞避免</h3><p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240308181540079.png" alt="image-20240308181540079"></p>
<h2 id="快速重传"><a href="#快速重传" class="headerlink" title="快速重传"></a>快速重传</h2><p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240308181628519.png" alt="image-20240308181628519"></p>
<h2 id="快速恢复"><a href="#快速恢复" class="headerlink" title="快速恢复"></a>快速恢复</h2><p>当收到三次重复的 ACK 时，进入快速恢复阶段，解释为轻度网络拥塞</p>
<ul>
<li>拥塞阈值 ssthresh 降低为 cwnd 的一半</li>
<li>拥塞窗口 cwnd 设置为 ssthresh</li>
<li>拥塞窗口线性增加</li>
</ul>
<h1 id="HTTP-协议"><a href="#HTTP-协议" class="headerlink" title="HTTP 协议"></a>HTTP 协议</h1><h2 id="报文结构"><a href="#报文结构" class="headerlink" title="报文结构"></a>报文结构</h2><ul>
<li>起始行</li>
<li>头部</li>
<li>空行</li>
<li>实体</li>
</ul>
<h2 id="如何用-TCP-发送-HTTP-请求"><a href="#如何用-TCP-发送-HTTP-请求" class="headerlink" title="如何用 TCP 发送 HTTP 请求"></a>如何用 TCP 发送 HTTP 请求</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">telnet www.baidu.com 80</span><br><span class="line"></span><br><span class="line">GET /HTTP/1.1</span><br><span class="line">Host:www.baidu.com</span><br><span class="line">User-Agent:curl/7.79.1</span><br><span class="line">Accept:*/*</span><br></pre></td></tr></table></figure>

<h3 id="请求行"><a href="#请求行" class="headerlink" title="请求行"></a>请求行</h3><blockquote>
<p>  GET &#x2F; HTTP&#x2F;1.1</p>
</blockquote>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240310090650572.png" alt="image-20240310090650572"></p>
<ul>
<li>Method：GET、POST…</li>
<li>SP： space</li>
<li>URI：请求地址</li>
<li>Version：HTTP 版本</li>
<li>CRLF：换行符</li>
</ul>
<h3 id="状态行"><a href="#状态行" class="headerlink" title="状态行"></a>状态行</h3><blockquote>
<p>  HTTP&#x2F;1.1 200 OK</p>
</blockquote>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240310090809584.png" alt="image-20240310090809584"></p>
<ul>
<li>Version：HTTP 版本</li>
<li>Status Code：状态码</li>
<li>Reason：状态码对应的解释</li>
</ul>
<h3 id="头部"><a href="#头部" class="headerlink" title="头部"></a>头部</h3><blockquote>
<p>  Host: <a target="_blank" rel="noopener" href="http://www.baidu.com/">www.baidu.com</a><br>  User-Agent: curl&#x2F;7.79.1<br>  Accept: *&#x2F;*</p>
</blockquote>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240310091122468.png" alt="image-20240310091122468"></p>
<h2 id="请求方法"><a href="#请求方法" class="headerlink" title="请求方法"></a>请求方法</h2><ul>
<li>GET：获取资源，读取或下载数据</li>
<li>HEAD：获取资源的元信息</li>
<li>POST：向资源提交数据</li>
<li>PUT：类似 POST</li>
<li>DELETE：删除资源</li>
<li>CONNECT：建立特殊的连接隧道</li>
<li>OPTIONS：列出可对资源实行的方法</li>
<li>TRACE：追踪请求 - 响应的传输路径</li>
</ul>
<h3 id="用-HEAD-判断url是否存在"><a href="#用-HEAD-判断url是否存在" class="headerlink" title="用 HEAD 判断url是否存在"></a>用 HEAD 判断url是否存在</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -I https://abc.com/1.txt</span><br></pre></td></tr></table></figure>

<h2 id="状态码"><a href="#状态码" class="headerlink" title="状态码"></a>状态码</h2><ul>
<li>1xx：提示信息，表示目前是协议处理的中间状态，还需要后续的操作<ul>
<li>100 Continue：上传大文件前使用</li>
<li>101 Switch Protocols：协议升级使用，如升级 websocket 或 http&#x2F;2.0</li>
</ul>
</li>
<li>2xx：成功，报文已经收到并被正确处理<ul>
<li>200 OK：成功返回响应</li>
<li>202 Accepted：服务器接收并开始处理请求，但请求为处理完成</li>
<li>204 No Content：成功执行了请求且不携带响应包体</li>
<li>206 Partial Content：分块下载或断点续传的基础</li>
</ul>
</li>
<li>3xx：重定向，资源位置发生变动，需要客户端重新发送请求<ul>
<li>301 Moved Permanently：资源永久性重定向</li>
<li>302 Found：资源临时重定向</li>
<li>304 Not Modified：告诉客户端可以复用缓存</li>
</ul>
</li>
<li>4xx：客户端错误，请求报文有误，服务器无法处理<ul>
<li>400 Bad Request：客户端出现了错误</li>
<li>401 Unauthorized：用户认证信息缺失或不正确</li>
<li>403 Forbidden：无权限</li>
<li>404 Not Found：服务器没有找到对应的资源</li>
<li>405 Method Not Allowed：不允许使用某些方法操作资源，如不允许 POST 只能 GET</li>
</ul>
</li>
<li>5xx：服务器错误，服务器在处理请求是内部发生了错误<ul>
<li>500 Internal ServerError：服务器内部错误</li>
<li>502 Bad Gateway：代理服务器无法获取到合法响应</li>
<li>504 Service Unavailable：服务器忙，暂时无法响应服务</li>
<li>504 Getway Timeout：超时</li>
</ul>
</li>
</ul>
<h2 id="Connection-头部"><a href="#Connection-头部" class="headerlink" title="Connection 头部"></a>Connection 头部</h2><p>Keep_Alive：长连接</p>
<p>Close：短连接</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240310093352382.png" alt="image-20240310093352382"></p>
<h1 id="HTTP2-协议"><a href="#HTTP2-协议" class="headerlink" title="HTTP2 协议"></a>HTTP2 协议</h1><h2 id="HTTP-x2F-1-1时代的优化"><a href="#HTTP-x2F-1-1时代的优化" class="headerlink" title="HTTP&#x2F;1.1时代的优化"></a>HTTP&#x2F;1.1时代的优化</h2><ul>
<li><p><strong>持久连接</strong> (Keep Alive)：TCP 连接复用</p>
<ul>
<li>没有持久连接，每次请求都会导致两次往返延迟</li>
<li>避免第二次 TCP 连接时的三次握手、消除另一次 TCP 慢启动的往返</li>
</ul>
</li>
<li><p><strong>HTTP管道化</strong> (Http piplining)：把 FIFO 队列从客户端迁移到服务器 (基本不用)</p>
<ul>
<li>只能严格串行的返回响应，不允许一个连接上的多个响应数据交错到达 (多路复用)</li>
<li>一个慢响应会阻塞所有后续请求</li>
<li>并行处理请求是，服务器必须缓存管道中的响应，造成不必要的缓存开销，可能被利用来攻击服务器</li>
<li>如果 TCP 连接中断，客户端因为没有收到响应，可能会重发后续所有的请求，造成服务端重复处理</li>
<li>中间请求如果存在代理，代理不支持这个特性，会造成连接中断或者串行化</li>
</ul>
</li>
<li><p><strong>使用多个HTTP连接</strong>：每个 HTTP 连接独立于其他的 HTTP 连接，现在大多数浏览器为每个域名打开 6 个连接，为了突破单域名连接数的限制，很多网站或切分子域名提供静态资源</p>
<ul>
<li>多个连接客户端和服务端都有额外的开销</li>
<li>每个 TCP 连接都要经历建连、慢启动阶段</li>
<li>页面加载完以后，TCP 连接大部分用不到了 (74% 的连接仅传输一个会话)</li>
</ul>
</li>
<li><p><strong>发送更少的请求</strong></p>
<ul>
<li>组合：把多个js、css文件合并为一个文件</li>
<li>拼接：将多张图片合成一张更大的图片 (Sprite图)</li>
<li>资源嵌入：css，js等嵌入html中</li>
</ul>
</li>
</ul>
<h2 id="HTTP-x2F-2时代"><a href="#HTTP-x2F-2时代" class="headerlink" title="HTTP&#x2F;2时代"></a>HTTP&#x2F;2时代</h2><p>HTTP&#x2F;2是一个二进制的协议</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240310100314061.png" alt="image-20240310100314061"></p>
<ul>
<li>所有的通信都是在一个 TCP 连接上完成</li>
<li>流是连接中的一个虚拟信道，可以承载双向的消息；每个流都有一个唯一的整数标识符</li>
<li>消息是指逻辑上的 HTTP 消息，如请求、响应等，由一个或多个帧组成</li>
<li>帧是最小的通信单位，承载特定类型的数据，如 HTTP 首部、负荷等</li>
</ul>
<h3 id="多路复用代替同步请求"><a href="#多路复用代替同步请求" class="headerlink" title="多路复用代替同步请求"></a>多路复用代替同步请求</h3><p>HTTP2 在共享的连接上同时发送请求和响应</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240310100715142.png" alt="image-20240310100715142"></p>
<ul>
<li>每个请求都有新的、自增的 ID，返回响应使用相同的流 ID</li>
<li>为了防止流 ID冲突，客户端发起请求使用奇数流 ID、服务器端发起请求使用偶数流 ID</li>
</ul>
<h2 id="HTTP-x2F-2的优势"><a href="#HTTP-x2F-2的优势" class="headerlink" title="HTTP&#x2F;2的优势"></a>HTTP&#x2F;2的优势</h2><ul>
<li><p>可以并行交错地发送请求，请求之间互不影响</p>
</li>
<li><p>可以并行交错地发生响应，响应之间互不干扰</p>
</li>
<li><p>只使用一个连接即可并行发生多个请求和响应</p>
</li>
<li><p>消除不必要的延迟，从而减少页面加载的时间</p>
</li>
<li><p>不必再为绕过 HTTP&#x2F;1.x 限制而多做很多工作</p>
</li>
</ul>
<h2 id="优先级"><a href="#优先级" class="headerlink" title="优先级"></a>优先级</h2><ul>
<li>HTTP&#x2F;1.1时代，浏览器先请求关键资源，然后再请求非阻塞的内容，请求会进入队列，等待可用的 HTTP 连接，优先级由浏览器管理</li>
<li>HTTP&#x2F;2 许多请求不用再排队，可以立即发送 (没有优先级的处理)<ul>
<li>可能导致带宽浪费在较低优先级的资源，从而导致 HTTP&#x2F;2 下载页面的加载速度变慢，因此需要优先级</li>
<li>HTTP&#x2F;2 的优先级：数据帧在排队时，服务器会给高优先级的请求发送更多的帧</li>
</ul>
</li>
</ul>
<h2 id="首部压缩"><a href="#首部压缩" class="headerlink" title="首部压缩"></a>首部压缩</h2><p>首部臃肿：cookie、user-agent、accept、accept-encoding…</p>
<h3 id="HPACK"><a href="#HPACK" class="headerlink" title="HPACK"></a>HPACK</h3><h4 id="静态表"><a href="#静态表" class="headerlink" title="静态表"></a>静态表</h4><p>HTTP&#x2F;2 一共对61个常用的头、以及头和值的组合进行了编码</p>
<h4 id="动态表"><a href="#动态表" class="headerlink" title="动态表"></a>动态表</h4><p>允许客户端和服务端通过通信的方式，维护一张动态的”字典”，这样用索引号就可以代表遗传很长的文本，减少在这次 HTTP&#x2F;2 连接中反复出现的一些自定义字段的载荷</p>
<h4 id="huffman表-最优前缀编码"><a href="#huffman表-最优前缀编码" class="headerlink" title="huffman表 (最优前缀编码)"></a>huffman表 (最优前缀编码)</h4><p>出现概率更高的字符用更短的编码表示，出现概率更低的字符用较长的编码表示，并且规避了解码歧义问题 (不同的字符编码间不能彼此成为对方的前缀)</p>
<h1 id="websocket-协议"><a href="#websocket-协议" class="headerlink" title="websocket 协议"></a>websocket 协议</h1><p>HTTP协议缺陷：通信只能由客户端发起</p>
<h2 id="帧类型"><a href="#帧类型" class="headerlink" title="帧类型"></a>帧类型</h2><p>FIN：是消息结束的标志位，相当于 HTTP&#x2F;2 里的 END_STEAM，表示数据发送完毕</p>
<p>一个消息可以拆成多个帧，接收方看到 FIN 后，就可以把前面的帧拼接起来，组成完整的消息</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240310104629180.png" alt="image-20240310104629180"></p>
<p>MASK：表示帧内容是否使用异或操作做简单的加密。目前 WebSocket 标准规定，客户端发送数据必须使用掩码，而服务器发送则必须不使用掩码</p>
<p>Payload len：表示帧内容的长度，是另一种变长编码</p>
<h2 id="握手协议"><a href="#握手协议" class="headerlink" title="握手协议"></a>握手协议</h2><p>WebSocket 的握手是一个标准的 HTTP GET 请求，但到带上两个协议升级的专用头字段</p>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240310105720620.png" alt="image-20240310105720620"></p>
<ul>
<li><code>Connection: Upgrade</code>：表示要升级协议</li>
<li><code>Upgrade: websocket</code>：表示要升级到 websocket 协议</li>
<li><code>Sec-WebSocket-Version: 13</code>：表示 websocket 的版本</li>
<li><code>Sec-WebSOcket-Key:</code>：与后面服务端响应首部的 <code>Sec-WebSocket-Accept</code> 是配套的，提供基本的防护，如恶意的连接，或者无意的连接</li>
</ul>
<h2 id="总结-1"><a href="#总结-1" class="headerlink" title="总结"></a>总结</h2><ul>
<li>HTTP 的”请求-应答”模式不适合开发”实时通信”的应用，为了解决轮训的开销，出现了 WebSocket</li>
<li>WebSocket 使用兼容 HTTP 的 URI 来发泄服务，但定义了新的协议名”ws”和”wss”，端口号沿用了80和443</li>
<li>WebSocket 利用 HTTP 协议实现连接握手，发送 GET 请求要求”协议升级”</li>
</ul>
<h1 id="tcpdump"><a href="#tcpdump" class="headerlink" title="tcpdump"></a>tcpdump</h1><p>tcpdump是一个命令行的网络流量分析工具</p>
<h2 id="指定网卡"><a href="#指定网卡" class="headerlink" title="指定网卡"></a>指定网卡</h2><p><code>-i</code> 表示指定哪一个网卡，<code>any</code> 表示任意，有哪些网卡可以使用 <code>ifconfig/ip a</code> 查看。如果只想查看 eth0 网卡经过的数据包，可以使用 <code>tcpdump -i eth0</code> 命令进行查看</p>
<h2 id="过滤主机"><a href="#过滤主机" class="headerlink" title="过滤主机"></a>过滤主机</h2><ul>
<li><p><code>host</code> 只查看指定 ip 的网络包，这个 ip 可以是源地址也可以是目标地址</p>
<ul>
<li><code>tcpdump -i any host 192.168.95.1</code></li>
</ul>
</li>
<li><p><code>src</code> 抓取目标 ip 发出的包</p>
<ul>
<li><code>tcpdump -i any src 192.168.95.101</code></li>
</ul>
</li>
<li><p><code>dst</code> 抓取目标 ip 收到的包</p>
<ul>
<li><code>tcpdump -i any src 192.168.95.102</code></li>
</ul>
</li>
</ul>
<h2 id="过滤端口"><a href="#过滤端口" class="headerlink" title="过滤端口"></a>过滤端口</h2><ul>
<li><p><code>port</code> 抓取指定端口的数据包</p>
<ul>
<li><code>tcpdump -i any port 80</code></li>
</ul>
</li>
<li><p><code>dst port</code>抓取指定端口收到的包</p>
<ul>
<li><code>tcpdump -i any dst port 80</code></li>
</ul>
</li>
<li><p><code>portrange</code> 过滤区间内的所有端口的流量</p>
<ul>
<li><code>tcpdump -i any portrange 21-23</code></li>
</ul>
</li>
</ul>
<h2 id="禁用主机与端口解析"><a href="#禁用主机与端口解析" class="headerlink" title="禁用主机与端口解析"></a>禁用主机与端口解析</h2><p>-n (禁用主机解析)、-nn (禁用端口解析)</p>
<p>在 tcpdump中，默认会解析主机的主机名和端口映射，使用-nn 可以直接显示 ip + port</p>
<h2 id="过滤协议"><a href="#过滤协议" class="headerlink" title="过滤协议"></a>过滤协议</h2><ul>
<li><code>udp</code> 只抓取 udp 包<ul>
<li><code>tcpdump -i any udp -nn</code></li>
</ul>
</li>
</ul>
<h2 id="查看包体内容"><a href="#查看包体内容" class="headerlink" title="查看包体内容"></a>查看包体内容</h2><ul>
<li><p><code>-A</code> 可以用 ASCII 打印报文内容，比如常用的 HTTP 协议传输 JSON、HTML 文件等都可以用这个选项</p>
<ul>
<li><code>tcpdump -i any -nn port 80 -A</code></li>
</ul>
</li>
<li><p><code>-X</code> 同时用 HEX 和 ASCII 显示报文内容</p>
<ul>
<li><code>tcpdump -i any -nn port 80 -X</code></li>
</ul>
</li>
</ul>
<h2 id="限制包大小"><a href="#限制包大小" class="headerlink" title="限制包大小"></a>限制包大小</h2><ul>
<li><code>-s</code> 当包体很大，可以用 <code>-s</code> 选项截取部分报文内容，一般都跟 <code>-A</code> 一同使用。查看每个包体前 500 字节使用以下命令<ul>
<li><code>tcpdump -i any -nn port 80 -A -s 500</code></li>
<li>如果想要显示包体所有内容，使用 <code>-s 0</code></li>
</ul>
</li>
</ul>
<h2 id="抓取特定数量的包"><a href="#抓取特定数量的包" class="headerlink" title="抓取特定数量的包"></a>抓取特定数量的包</h2><ul>
<li><code>-c</code> 抓取指定数量的报文，然后退出。抓取10个包<ul>
<li><code>tcpdump -i -any -nn port 80 -c 10</code></li>
</ul>
</li>
</ul>
<h2 id="数据报文输出到文件"><a href="#数据报文输出到文件" class="headerlink" title="数据报文输出到文件"></a>数据报文输出到文件</h2><ul>
<li><code>-w</code> 选项用来把数据报文输出到文件<ul>
<li><code>tcpdump -i any port 80 -w test.pcap</code></li>
<li>生产的 pcap 文件可以使用 wireshark 打开进行详细的分析，也可以加上 <code>-U</code> 强制立即写到本地磁盘，性能较差</li>
</ul>
</li>
</ul>
<h2 id="显示绝对的序号"><a href="#显示绝对的序号" class="headerlink" title="显示绝对的序号"></a>显示绝对的序号</h2><ul>
<li><code>-S</code> 默认情况下，tcpdump 显示的是从 0 开始的相对序号，如果想查看真正的绝对序号，使用 <code>-S</code> 选项<ul>
<li><code>tcpdump -i any port 80 -nn -S</code></li>
<li>没有 <code>-S</code> 时的输出，seq 和 ack 都是从 0 开始</li>
</ul>
</li>
</ul>
<h2 id="高级技巧"><a href="#高级技巧" class="headerlink" title="高级技巧"></a>高级技巧</h2><ul>
<li><p>tcpdump 可以使用布尔运算符 (and &amp;&amp;、or ||、not ！) 组合出任意复杂的过滤器</p>
<ul>
<li><p>eg：</p>
</li>
<li><p>抓取指定 ip 到 3306 端口的数据包<br><code>tcpdump -i any host 10.211.55.11 and dst port 3306</code></p>
</li>
<li><p>抓取指定 ip 目标端口除了 22 以外的所有包<br><code>tcpdump -i any src 11.211.33.12 and not dst port 22</code></p>
</li>
</ul>
</li>
<li><p>tcpdump 可以使用 <code>()</code> 进行条件分组，但是需要把组合条件使用 ‘’ 包裹</p>
<ul>
<li><p>eg：</p>
</li>
<li><p>抓取指定源 ip 且目标端口为 3306 或 6379 的包<br><code>tcpdump -i any &#39;src 11.211.33.12 and (dst port 3306 or 6379)&#39;</code></p>
</li>
</ul>
</li>
</ul>
<p><img src="https://gitee-blog-1317332932.cos.ap-nanjing.myqcloud.com/imgs/image-20240310150832708.png" alt="image-20240310150832708"></p>
<ul>
<li><p>过滤所有的 RST 包 <code>tcpdump &#39;tcp[13] &amp; 4 != 0&#39;</code></p>
<ul>
<li>因为 TCP 首部中 offset 为 13 的字节的第 3 比特位就是 RST</li>
<li>4 &#x3D; b0100</li>
</ul>
</li>
<li><p>过滤  SYN+ACK 包，那么就是 SYN 和 ACK 包同时置位</p>
<ul>
<li><code>tcpdump &#39;tcp[13] &amp; 18 != 0&#39;</code></li>
</ul>
</li>
</ul>
<h1 id="常用网络工具"><a href="#常用网络工具" class="headerlink" title="常用网络工具"></a>常用网络工具</h1><h2 id="telnet"><a href="#telnet" class="headerlink" title="telnet"></a>telnet</h2><h3 id="检查端口是否打开"><a href="#检查端口是否打开" class="headerlink" title="检查端口是否打开"></a>检查端口是否打开</h3><p>telnet 的一个最大作用就是检查一个端口是否处于打开状态，使用的命令是 <code>telnet [domainname or ip] [port]</code>，这条命令意思是检查远端 server 的指定端口连接是否可达</p>
<p>第一个参数是要连接的域名或 ip，第二个参数是要连接的端口</p>
<p>如果这个网络连接可打，则会提示 <code>Connected to ...</code>；如果网络不可达，则会显示 <code>Unable to connect ... connection refused</code></p>
<h3 id="telnet-发送-http-请求"><a href="#telnet-发送-http-请求" class="headerlink" title="telnet 发送 http 请求"></a>telnet 发送 http 请求</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">telnet www.baidu.com</span><br><span class="line">GET / HTTP/1.1</span><br><span class="line">Host: www.baidu.com</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h3 id="telnet-连接-Redis"><a href="#telnet-连接-Redis" class="headerlink" title="telnet 连接 Redis"></a>telnet 连接 Redis</h3><p>假设 redis 服务器运行在本地，监听 6379 端口，使用 telnet localhost 6379 命令可以连接</p>
<h2 id="nc"><a href="#nc" class="headerlink" title="nc"></a>nc</h2><p>netcat 因为功能强大，被称为网络工具中的瑞士军刀，nc 是 netcat 的简称</p>
<h3 id="用-nc-充当网络聊天器"><a href="#用-nc-充当网络聊天器" class="headerlink" title="用 nc 充当网络聊天器"></a>用 nc 充当网络聊天器</h3><p><code>nc -l port</code></p>
<p>快速启动一个 TCP server 监听某个端口</p>
<h3 id="发送-http-请求"><a href="#发送-http-请求" class="headerlink" title="发送 http 请求"></a>发送 http 请求</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">nc www.baidu.com 80</span><br><span class="line">GET / HTTP/1.1</span><br><span class="line">Host: www.baidu.com</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h3 id="查看远程端口是否打开"><a href="#查看远程端口是否打开" class="headerlink" title="查看远程端口是否打开"></a>查看远程端口是否打开</h3><p><code>nc -zv [host or ip] [port]</code></p>
<p><code>-z</code> 表示不发送任何数据包，TCP 三次握手后自动退出进程。<code>-v</code> 参数会输出更多详细信息 (verbose)</p>
<h2 id="netstat"><a href="#netstat" class="headerlink" title="netstat"></a>netstat</h2><p>netstat 可以用来显示套接字的状态</p>
<h3 id="列出所有的套接字"><a href="#列出所有的套接字" class="headerlink" title="列出所有的套接字"></a>列出所有的套接字</h3><p><code>netstat -a</code></p>
<h3 id="只列出-TCP-套接字"><a href="#只列出-TCP-套接字" class="headerlink" title="只列出 TCP 套接字"></a>只列出 TCP 套接字</h3><p><code>netstat -at/--tcp</code></p>
<h3 id="只列出-UDP-套接字"><a href="#只列出-UDP-套接字" class="headerlink" title="只列出 UDP 套接字"></a>只列出 UDP 套接字</h3><p><code>netstat -au/--udp</code></p>
<h3 id="只列出处于-listen-状态的连接"><a href="#只列出处于-listen-状态的连接" class="headerlink" title="只列出处于 listen 状态的连接"></a>只列出处于 listen 状态的连接</h3><p><code>netstat -l</code></p>
<p>过滤处于 listen 状态的 TCP 连接 <code>netstat -lt</code></p>
<h3 id="禁用端口和IP映射"><a href="#禁用端口和IP映射" class="headerlink" title="禁用端口和IP映射"></a>禁用端口和IP映射</h3><p><code>netstat -n</code></p>
<h3 id="显示进程"><a href="#显示进程" class="headerlink" title="显示进程"></a>显示进程</h3><p><code>netstat -p</code></p>
<h3 id="显示所有的网卡信息"><a href="#显示所有的网卡信息" class="headerlink" title="显示所有的网卡信息"></a>显示所有的网卡信息</h3><p><code>netstat -i</code></p>
<h3 id="统计处于各个状态的连接个数"><a href="#统计处于各个状态的连接个数" class="headerlink" title="统计处于各个状态的连接个数"></a>统计处于各个状态的连接个数</h3><p><code>netstat -ant | awk &#39;&#123;print $6&#125; | sort | uniq -c | sort -n&#39;</code></p>
<ul>
<li><p><code>netstat -ant</code>: 运行 netstat 命令，显示当前系统中的所有 TCP 连接，并且不解析服务名称，而是显示数字形式的 IP 地址和端口号。</p>
</li>
<li><p><code>awk &#39;&#123;print $6&#125;&#39;</code>: 使用 awk 命令提取 netstat 命令输出的结果中的第六列，也就是 TCP 连接的状态（如 ESTABLISHED、TIME_WAIT 等）。</p>
</li>
<li><p><code>sort</code>: 对提取出来的 TCP 连接状态进行排序。</p>
</li>
<li><p><code>uniq -c</code>: 统计相同的行，并显示其出现的次数。</p>
</li>
<li><p><code>sort -n</code>: 对出现次数进行数值排序，从而得到一个按连接状态统计数量的列表。</p>
</li>
</ul>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="https://crappier.github.io">fanhao</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://crappier.github.io/2024/03/10/TCP%E5%8D%8F%E8%AE%AE/">https://crappier.github.io/2024/03/10/TCP%E5%8D%8F%E8%AE%AE/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://crappier.github.io" target="_blank">Depicter</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/">计算机网络</a></div><div class="post_share"><div class="social-share" data-image="/img/cover/cover_9.jpg" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/js/social-share.min.js" defer></script></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/2024/03/12/Nmap%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/" title="Nmap使用指南"><img class="cover" src="/img/cover/cover_2.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">Nmap使用指南</div></div></a></div><div class="next-post pull-right"><a href="/2024/03/06/%E5%B8%B8%E7%94%A8%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8%E8%AE%BE%E5%A4%87/" title="常用网络安全设备"><img class="cover" src="/img/cover/cover_6.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">常用网络安全设备</div></div></a></div></nav></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="/img/avatar.jpg" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">fanhao</div><div class="author-info__description"></div></div><div class="card-info-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">10</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">5</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">0</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://gitee.com/fanhao0416"><i class="fab fa-gitee"></i><span>联系我</span></a><div class="card-info-social-icons is-center"><a class="social-icon" href="https://gitee.com/fanhao0416" target="_blank" title="Gitee"><i class="fab fa-git" style="color: #DC143C;"></i></a><a class="social-icon" href="mailto:2039216364@qq.com" target="_blank" title="Email"><i class="fas fa-envelope" style="color: #4a7dbe;"></i></a><a class="social-icon" href="http://wpa.qq.com/msgrd?v=3&amp;uin=2039216364&amp;site=qq&amp;menu=yes" target="_blank" title="QQ"><i class="fab fa-qq" style="color: #4a7dbe;"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">沧海易幻莫同，世人皆平庸</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#TCP-x2F-IP%E5%8D%8F%E8%AE%AE"><span class="toc-number">1.</span> <span class="toc-text">TCP&#x2F;IP协议</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%BA%94%E7%94%A8%E5%B1%82-Application-Layer"><span class="toc-number">1.1.</span> <span class="toc-text">应用层 Application Layer</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BC%A0%E8%BE%93%E5%B1%82-Transportation-Layer"><span class="toc-number">1.2.</span> <span class="toc-text">传输层 Transportation Layer</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BD%91%E7%BB%9C%E4%BA%92%E8%BF%9E%E5%B1%82-Internet-Layer"><span class="toc-number">1.3.</span> <span class="toc-text">网络互连层 Internet Layer</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BD%91%E7%BB%9C%E8%AE%BF%E9%97%AE%E5%B1%82-Network-Access-Layer"><span class="toc-number">1.4.</span> <span class="toc-text">网络访问层 Network Access Layer</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%88%86%E5%B1%82%E7%9A%84%E4%BC%98%E5%8A%BF"><span class="toc-number">1.5.</span> <span class="toc-text">分层的优势</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#TCP%E5%8D%8F%E8%AE%AE"><span class="toc-number">2.</span> <span class="toc-text">TCP协议</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%9D%A2%E5%90%91%E8%BF%9E%E6%8E%A5"><span class="toc-number">2.1.</span> <span class="toc-text">面向连接</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#IP%E5%8D%8F%E8%AE%AE"><span class="toc-number">2.2.</span> <span class="toc-text">IP协议</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#TCP%E5%8D%8F%E8%AE%AE%E6%98%AF%E2%80%9C%E5%8F%AF%E9%9D%A0%E7%9A%84%E2%80%9D"><span class="toc-number">2.3.</span> <span class="toc-text">TCP协议是“可靠的”</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#TCP%E6%98%AF%E4%B8%80%E4%B8%AA%E6%B5%81%E5%8D%8F%E8%AE%AE"><span class="toc-number">2.4.</span> <span class="toc-text">TCP是一个流协议</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%AE%B0%E5%BD%95%E8%BE%B9%E7%95%8C%E6%A0%87%E8%AF%86"><span class="toc-number">2.5.</span> <span class="toc-text">记录边界标识</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#TCP%E6%98%AF%E5%85%A8%E5%8F%8C%E5%B7%A5%E7%9A%84%E5%8D%8F%E8%AE%AE"><span class="toc-number">2.6.</span> <span class="toc-text">TCP是全双工的协议</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#TCP-%E5%8F%AF%E9%9D%A0%E6%80%A7"><span class="toc-number">2.7.</span> <span class="toc-text">TCP 可靠性</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#WireShark"><span class="toc-number">3.</span> <span class="toc-text">WireShark</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%8A%93%E5%8C%85"><span class="toc-number">3.1.</span> <span class="toc-text">抓包</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#WireShark%E4%BD%BF%E7%94%A8"><span class="toc-number">3.2.</span> <span class="toc-text">WireShark使用</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%8D%95%E8%8E%B7%E8%BF%87%E6%BB%A4%E5%99%A8-capture-filter"><span class="toc-number">3.2.1.</span> <span class="toc-text">捕获过滤器 capture filter</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%98%BE%E7%A4%BA%E8%BF%87%E6%BB%A4-display-filter"><span class="toc-number">3.2.2.</span> <span class="toc-text">显示过滤 display filter</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%B8%B8%E7%94%A8%E7%9A%84%E6%98%BE%E7%A4%BA%E8%BF%87%E6%BB%A4%E5%99%A8"><span class="toc-number">3.2.3.</span> <span class="toc-text">常用的显示过滤器</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#TCP%E7%9B%B8%E5%85%B3"><span class="toc-number">3.2.3.1.</span> <span class="toc-text">TCP相关</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#HTTP%E7%9B%B8%E5%85%B3"><span class="toc-number">3.2.3.2.</span> <span class="toc-text">HTTP相关</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%80%9A%E4%BF%A1%E5%BB%B6%E8%BF%9F%E5%B8%B8%E7%94%A8%E8%BF%87%E6%BB%A4%E5%99%A8"><span class="toc-number">3.2.3.3.</span> <span class="toc-text">通信延迟常用过滤器</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%8A%93%E5%8F%96-HTTPS-%E5%8C%85"><span class="toc-number">3.2.3.4.</span> <span class="toc-text">抓取 HTTPS 包</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#WireShark%E5%86%99%E6%8F%92%E4%BB%B6"><span class="toc-number">3.2.3.5.</span> <span class="toc-text">WireShark写插件</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#TCP-%E5%8D%8F%E8%AE%AE%E7%9A%84%E9%A6%96%E9%83%A8%E5%AD%97%E6%AE%B5"><span class="toc-number">4.</span> <span class="toc-text">TCP 协议的首部字段</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%BA%8F%E5%88%97%E5%8F%B7-sequence-number"><span class="toc-number">4.1.</span> <span class="toc-text">序列号 sequence number</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B%E7%9A%84-ISN-%E4%BA%A4%E6%8D%A2"><span class="toc-number">4.2.</span> <span class="toc-text">三次握手的 ISN 交换</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%BA%8F%E5%88%97%E5%8F%B7%E5%9B%9E%E7%BB%95"><span class="toc-number">4.3.</span> <span class="toc-text">序列号回绕</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%A1%AE%E8%AE%A4%E5%8F%B7-ack"><span class="toc-number">4.4.</span> <span class="toc-text">确认号 ack</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#TCP-Flags"><span class="toc-number">4.5.</span> <span class="toc-text">TCP Flags</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AA%97%E5%8F%A3%E5%A4%A7%E5%B0%8F"><span class="toc-number">4.6.</span> <span class="toc-text">窗口大小</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#TCP-%E7%AA%97%E5%8F%A3%E7%BC%A9%E6%94%BE-window-scale"><span class="toc-number">4.7.</span> <span class="toc-text">TCP 窗口缩放 window scale</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8F%AF%E9%80%89%E9%A1%B9-options%E3%80%81padding"><span class="toc-number">4.8.</span> <span class="toc-text">可选项 options、padding</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E7%AB%AF%E5%8F%A3%E5%8F%B7"><span class="toc-number">5.</span> <span class="toc-text">端口号</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%9B%B8%E5%85%B3%E5%91%BD%E4%BB%A4"><span class="toc-number">5.1.</span> <span class="toc-text">相关命令</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%9F%A5%E7%9C%8B%E5%AF%B9%E6%96%B9%E7%AB%AF%E5%8F%A3%E6%98%AF%E5%90%A6%E5%BC%80%E5%90%AF"><span class="toc-number">5.1.1.</span> <span class="toc-text">查看对方端口是否开启</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%9F%A5%E7%9C%8B%E7%AB%AF%E5%8F%A3%E8%A2%AB%E4%BB%80%E4%B9%88%E8%BF%9B%E7%A8%8B%E7%9B%91%E5%90%AC%E5%8D%A0%E7%94%A8"><span class="toc-number">5.1.2.</span> <span class="toc-text">查看端口被什么进程监听占用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%9F%A5%E7%9C%8B%E8%BF%9B%E7%A8%8B%E7%9B%91%E5%90%AC%E7%9A%84%E7%AB%AF%E5%8F%A3%E5%8F%B7"><span class="toc-number">5.1.3.</span> <span class="toc-text">查看进程监听的端口号</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%88%A9%E7%94%A8-x2F-proc-x2F-pid%E6%89%93%E5%BC%80%E6%96%87%E4%BB%B6%E5%88%97%E8%A1%A8"><span class="toc-number">5.1.4.</span> <span class="toc-text">利用&#x2F;proc&#x2F;pid打开文件列表</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%88%A9%E7%94%A8%E7%AB%AF%E5%8F%A3%E8%BF%9B%E8%A1%8C%E7%BD%91%E7%BB%9C%E6%94%BB%E5%87%BB"><span class="toc-number">5.2.</span> <span class="toc-text">利用端口进行网络攻击</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%A6%82%E6%9E%9C%E4%B8%B4%E6%97%B6%E7%AB%AF%E5%8F%A3%E5%8F%B7%E5%88%86%E9%85%8D%E5%AE%8C%E4%BC%9A%E5%8F%91%E7%94%9F%E4%BB%80%E4%B9%88"><span class="toc-number">5.3.</span> <span class="toc-text">如果临时端口号分配完会发生什么</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%B4%E6%97%B6%E7%AB%AF%E5%8F%A3%E5%8F%B7%E5%A6%82%E4%BD%95%E5%88%86%E9%85%8D"><span class="toc-number">5.4.</span> <span class="toc-text">临时端口号如何分配</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%9C%80%E8%A6%81%E5%88%86%E9%85%8D%E7%AB%AF%E5%8F%A3%E7%9A%84%E6%83%85%E5%86%B5"><span class="toc-number">5.4.1.</span> <span class="toc-text">需要分配端口的情况</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#TCP-%E5%8D%8F%E8%AE%AE%E6%A0%88%E7%94%A8%E5%85%A8%E5%B1%80%E7%9A%843%E4%B8%AA%E5%93%88%E5%B8%8C%E8%A1%A8-inet-hash-tables"><span class="toc-number">5.4.2.</span> <span class="toc-text">TCP 协议栈用全局的3个哈希表 inet_hash_tables</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%95%B0%E7%BB%84-%E9%93%BE%E8%A1%A8%E5%AE%9E%E7%8E%B0%E5%93%88%E5%B8%8C%E7%BB%93%E6%9E%84"><span class="toc-number">5.4.2.1.</span> <span class="toc-text">数组+链表实现哈希结构</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%AB%98%E7%89%88%E6%9C%AC%E5%86%85%E6%A0%B8%E4%B8%B4%E6%97%B6%E7%AB%AF%E5%8F%A3%E5%88%86%E9%85%8D%E7%AD%96%E7%95%A5"><span class="toc-number">5.4.3.</span> <span class="toc-text">高版本内核临时端口分配策略</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%80%A7%E8%83%BD%E8%A1%B0%E5%87%8F%E6%80%BB%E7%BB%93"><span class="toc-number">5.4.4.</span> <span class="toc-text">性能衰减总结</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%8D%8F%E8%AE%AE%E6%A0%88%E6%B5%8B%E8%AF%95-packetdrill"><span class="toc-number">6.</span> <span class="toc-text">协议栈测试 - packetdrill</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%84%9A%E6%9C%AC%E6%A0%BC%E5%BC%8F-%E6%97%B6%E9%97%B4"><span class="toc-number">6.1.</span> <span class="toc-text">脚本格式-时间</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%80%90%E8%A1%8C%E8%A7%A3%E6%9E%90"><span class="toc-number">6.2.</span> <span class="toc-text">逐行解析</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%AC%AC1%E8%A1%8C"><span class="toc-number">6.2.1.</span> <span class="toc-text">第1行</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%AC%AC2%E8%A1%8C"><span class="toc-number">6.2.2.</span> <span class="toc-text">第2行</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%AC%AC3%E8%A1%8C"><span class="toc-number">6.2.3.</span> <span class="toc-text">第3行</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%AC%AC4%E8%A1%8C"><span class="toc-number">6.2.4.</span> <span class="toc-text">第4行</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B"><span class="toc-number">6.2.5.</span> <span class="toc-text">三次握手</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#packetdrill-%E5%8E%9F%E7%90%86"><span class="toc-number">6.3.</span> <span class="toc-text">packetdrill 原理</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#packetdrill-%E8%AF%AD%E6%B3%95%E8%A7%A3%E6%9E%90"><span class="toc-number">6.3.1.</span> <span class="toc-text">packetdrill 语法解析</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#TUN-x2F-TAP-%E8%AE%BE%E5%A4%87"><span class="toc-number">6.3.2.</span> <span class="toc-text">TUN&#x2F;TAP 设备</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#tun-x2F-tap%E8%AE%BE%E5%A4%87%E4%B8%8E%E7%89%A9%E7%90%86%E7%BD%91%E5%8D%A1%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="toc-number">6.3.3.</span> <span class="toc-text">tun&#x2F;tap设备与物理网卡的区别</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B-1"><span class="toc-number">7.</span> <span class="toc-text">三次握手</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AC%AC%E4%B8%80%E6%AD%A5%EF%BC%9A%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%8F%91%E9%80%81-SYN"><span class="toc-number">7.1.</span> <span class="toc-text">第一步：客户端发送 SYN</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%B8%BA%E4%BB%80%E4%B9%88-SYN-%E6%AE%B5%E4%B8%8D%E6%90%BA%E5%B8%A6%E6%95%B0%E6%8D%AE%E5%8D%B4%E8%A6%81%E6%B6%88%E8%80%97%E4%B8%80%E4%B8%AA%E5%BA%8F%E5%88%97%E5%8F%B7"><span class="toc-number">7.1.1.</span> <span class="toc-text">为什么 SYN 段不携带数据却要消耗一个序列号</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AC%AC%E4%BA%8C%E6%AD%A5%EF%BC%9A%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%9B%9E%E5%A4%8D-SYN-ACK"><span class="toc-number">7.2.</span> <span class="toc-text">第二步：服务端回复 SYN+ACK</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AC%AC%E4%B8%89%E6%AD%A5%EF%BC%9A%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%9B%9E%E5%A4%8D-ACK"><span class="toc-number">7.3.</span> <span class="toc-text">第三步：客户端回复 ACK</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B%E8%BF%98%E4%BA%A4%E6%8D%A2%E4%BA%86%E4%BB%80%E4%B9%88"><span class="toc-number">7.4.</span> <span class="toc-text">三次握手还交换了什么</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%88%9D%E5%A7%8B-ISN-%E7%94%9F%E6%88%90%E7%AE%97%E6%B3%95"><span class="toc-number">7.5.</span> <span class="toc-text">初始 ISN 生成算法</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#ISN-%E8%AE%BE%E7%BD%AE%E4%B8%BA%E5%9B%BA%E5%AE%9A%E5%80%BC%E4%BA%A7%E7%94%9F%E7%9A%84%E9%97%AE%E9%A2%98"><span class="toc-number">7.6.</span> <span class="toc-text">ISN 设置为固定值产生的问题</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B%E4%B8%AD%E7%9A%84%E7%8A%B6%E6%80%81%E5%8F%98%E8%BF%81"><span class="toc-number">7.7.</span> <span class="toc-text">三次握手中的状态变迁</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%A6%82%E6%9E%9C%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%8F%91%E9%80%81-SYN-%E5%8C%85%EF%BC%8C%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%B2%A1%E6%9C%89%E5%9B%9E%E5%A4%8D-ACK"><span class="toc-number">7.7.1.</span> <span class="toc-text">如果客户端发送 SYN 包，服务端没有回复 ACK</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%A4%E7%AB%AF%E5%90%8C%E6%97%B6%E5%8F%91%E8%B5%B7%E8%BF%9E%E6%8E%A5%E5%BB%BA%E7%AB%8B"><span class="toc-number">7.8.</span> <span class="toc-text">两端同时发起连接建立</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#TCP-%E8%87%AA%E8%BF%9E%E6%8E%A5"><span class="toc-number">7.9.</span> <span class="toc-text">TCP 自连接</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%9B%9B%E6%AC%A1%E6%8C%A5%E6%89%8B"><span class="toc-number">8.</span> <span class="toc-text">四次挥手</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AC%AC%E4%B8%80%E6%AD%A5"><span class="toc-number">8.1.</span> <span class="toc-text">第一步</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BB%80%E4%B9%88%E6%83%85%E5%86%B5%E4%B8%8B%E8%A7%A6%E5%8F%91-FIN-%E6%8A%A5%E6%96%87"><span class="toc-number">8.1.1.</span> <span class="toc-text">什么情况下触发 FIN 报文</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AC%AC%E4%BA%8C%E6%AD%A5"><span class="toc-number">8.2.</span> <span class="toc-text">第二步</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AC%AC%E4%B8%89%E6%AD%A5"><span class="toc-number">8.3.</span> <span class="toc-text">第三步</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AC%AC%E5%9B%9B%E6%AD%A5"><span class="toc-number">8.4.</span> <span class="toc-text">第四步</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%BA%E4%BB%80%E4%B9%88-FIN-%E6%8A%A5%E6%96%87%E8%A6%81%E6%B6%88%E8%80%97%E4%B8%80%E4%B8%AA%E5%BA%8F%E5%88%97%E5%8F%B7"><span class="toc-number">8.5.</span> <span class="toc-text">为什么 FIN 报文要消耗一个序列号</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E6%8C%A5%E6%89%8B%E8%A6%81%E5%9B%9B%E6%AC%A1%EF%BC%8C%E5%8F%98%E6%88%90%E4%B8%89%E6%AC%A1%E5%8F%AF%E4%BB%A5%E5%90%97"><span class="toc-number">8.6.</span> <span class="toc-text">为什么挥手要四次，变成三次可以吗</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%90%8C%E6%97%B6%E5%85%B3%E9%97%AD"><span class="toc-number">8.7.</span> <span class="toc-text">同时关闭</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#TCP-11%E7%A7%8D%E7%8A%B6%E6%80%81%E5%8F%98%E8%BF%81"><span class="toc-number">9.</span> <span class="toc-text">TCP 11种状态变迁</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#CLOSED"><span class="toc-number">9.1.</span> <span class="toc-text">CLOSED</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#LISTEN"><span class="toc-number">9.2.</span> <span class="toc-text">LISTEN</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#SYN-SENT"><span class="toc-number">9.3.</span> <span class="toc-text">SYN-SENT</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#SYN-RCVD"><span class="toc-number">9.4.</span> <span class="toc-text">SYN-RCVD</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#ESTABLISHED"><span class="toc-number">9.5.</span> <span class="toc-text">ESTABLISHED</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#FIN-WAIT-1"><span class="toc-number">9.6.</span> <span class="toc-text">FIN-WAIT-1</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#FIN-WAIT-2"><span class="toc-number">9.7.</span> <span class="toc-text">FIN-WAIT-2</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#CLOSE-WAIT-%E8%A2%AB%E5%8A%A8%E5%85%B3%E9%97%AD%E6%96%B9"><span class="toc-number">9.8.</span> <span class="toc-text">CLOSE-WAIT(被动关闭方)</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#TIME-WAIT-%E4%B8%BB%E5%8A%A8%E5%85%B3%E9%97%AD%E6%96%B9"><span class="toc-number">9.9.</span> <span class="toc-text">TIME-WAIT(主动关闭方)</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#LAST-ACK-%E8%A2%AB%E5%8A%A8%E5%85%B3%E9%97%AD%E6%96%B9"><span class="toc-number">9.10.</span> <span class="toc-text">LAST-ACK(被动关闭方)</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#CLOSING"><span class="toc-number">9.11.</span> <span class="toc-text">CLOSING</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B%E7%9A%84%E7%A7%98%E5%AF%86"><span class="toc-number">10.</span> <span class="toc-text">三次握手的秘密</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#backlog%E3%80%81%E5%8D%8A%E8%BF%9E%E6%8E%A5%E9%98%9F%E5%88%97%E3%80%81%E5%85%A8%E8%BF%9E%E6%8E%A5%E9%98%9F%E5%88%97"><span class="toc-number">10.1.</span> <span class="toc-text">backlog、半连接队列、全连接队列</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8D%8A%E8%BF%9E%E6%8E%A5%E9%98%9F%E5%88%97-QYN-Queue"><span class="toc-number">10.1.1.</span> <span class="toc-text">半连接队列 (QYN Queue)</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%85%A8%E8%BF%9E%E6%8E%A5%E9%98%9F%E5%88%97-Accept-Queue"><span class="toc-number">10.1.2.</span> <span class="toc-text">全连接队列 (Accept Queue)</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#ss%E5%91%BD%E4%BB%A4"><span class="toc-number">10.2.</span> <span class="toc-text">ss命令</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#backlog-%E7%9A%84%E5%8F%96%E5%80%BC"><span class="toc-number">10.3.</span> <span class="toc-text">backlog 的取值</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#tcp-abort-on-overflow-%E5%8F%82%E6%95%B0"><span class="toc-number">10.4.</span> <span class="toc-text">tcp_abort_on_overflow 参数</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#TCP-%E5%8D%8F%E8%AE%AE%E6%A0%88%E7%9A%84%E5%AE%9A%E6%97%B6%E5%99%A8"><span class="toc-number">11.</span> <span class="toc-text">TCP 协议栈的定时器</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%BF%9E%E6%8E%A5%E5%BB%BA%E7%AB%8B%E5%AE%9A%E6%97%B6%E5%99%A8-conection-establishment"><span class="toc-number">11.1.</span> <span class="toc-text">连接建立定时器 conection establishment</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%87%8D%E4%BC%A0%E5%AE%9A%E6%97%B6%E5%99%A8-retransmission"><span class="toc-number">11.2.</span> <span class="toc-text">重传定时器 retransmission</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%BB%B6%E8%BF%9F-ACK-%E5%AE%9A%E6%97%B6%E5%99%A8"><span class="toc-number">11.3.</span> <span class="toc-text">延迟 ACK 定时器</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#persist-%E5%AE%9A%E6%97%B6%E5%99%A8-zero-window"><span class="toc-number">11.4.</span> <span class="toc-text">persist 定时器 (zero window)</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BF%9D%E6%B4%BB%E5%AE%9A%E6%97%B6%E5%99%A8-keepalive-timer"><span class="toc-number">11.5.</span> <span class="toc-text">保活定时器 keepalive timer</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#FIN-WAIT-2-%E5%AE%9A%E6%97%B6%E5%99%A8"><span class="toc-number">11.6.</span> <span class="toc-text">FIN-WAIT-2 定时器</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#TIME-WAIT-%E5%AE%9A%E6%97%B6%E5%99%A8"><span class="toc-number">11.7.</span> <span class="toc-text">TIME-WAIT 定时器</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#TIME-WAIT-%E7%8A%B6%E6%80%81"><span class="toc-number">12.</span> <span class="toc-text">TIME-WAIT 状态</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#MSL-MAX-Segment-Lifetime"><span class="toc-number">12.1.</span> <span class="toc-text">MSL: MAX Segment Lifetime</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#TIME-WAIT-%E5%AD%98%E5%9C%A8%E7%9A%84%E5%8E%9F%E5%9B%A0"><span class="toc-number">12.2.</span> <span class="toc-text">TIME-WAIT 存在的原因</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E6%97%B6%E9%97%B4%E6%98%AF%E4%B8%A4%E4%B8%AA-MSL"><span class="toc-number">12.3.</span> <span class="toc-text">为什么时间是两个 MSL</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#TIME-WAIT-%E7%9A%84%E9%97%AE%E9%A2%98"><span class="toc-number">12.4.</span> <span class="toc-text">TIME-WAIT 的问题</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%BF%9E%E6%8E%A5%E8%A1%A8%E6%97%A0%E6%B3%95%E5%A4%8D%E7%94%A8"><span class="toc-number">12.4.1.</span> <span class="toc-text">连接表无法复用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%BA%94%E5%AF%B9-TIME-WAIT%E7%9A%84%E6%93%8D%E4%BD%9C"><span class="toc-number">12.4.2.</span> <span class="toc-text">应对 TIME-WAIT的操作</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#TCP-%E5%A4%B4%E9%83%A8%E6%97%B6%E9%97%B4%E6%88%B3%E9%80%89%E9%A1%B9-TCP-Timestamps-Option-TSopt"><span class="toc-number">12.4.3.</span> <span class="toc-text">TCP 头部时间戳选项 (TCP Timestamps Option, TSopt)</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#tcp-tw-reuse-%E9%80%89%E9%A1%B9"><span class="toc-number">12.4.4.</span> <span class="toc-text">tcp_tw_reuse 选项</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#tcp-tw-recyle-%E9%80%89%E9%A1%B9"><span class="toc-number">12.4.5.</span> <span class="toc-text">tcp_tw_recyle 选项</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#NAT"><span class="toc-number">12.4.6.</span> <span class="toc-text">NAT</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%BD%93-tcp-tw-recycle-%E9%81%87%E4%B8%8A-NAT"><span class="toc-number">12.4.7.</span> <span class="toc-text">当 tcp_tw_recycle 遇上 NAT</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#TIME-WAIT-%E5%AD%98%E5%9C%A8%E7%9A%84%E6%84%8F%E4%B9%89"><span class="toc-number">12.4.8.</span> <span class="toc-text">TIME-WAIT 存在的意义</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#SYN-Flood-SYN-%E6%B3%9B%E6%B4%AA%E6%94%BB%E5%87%BB"><span class="toc-number">13.</span> <span class="toc-text">SYN Flood (SYN 泛洪攻击)</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#Scapy-%E5%B7%A5%E5%85%B7"><span class="toc-number">13.1.</span> <span class="toc-text">Scapy 工具</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#scapy-%E6%9E%84%E9%80%A0%E6%95%B0%E6%8D%AE%E5%8C%85%E7%9A%84%E6%96%B9%E5%BC%8F"><span class="toc-number">13.2.</span> <span class="toc-text">scapy 构造数据包的方式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%8E%A5%E6%94%B6%E6%95%B0%E6%8D%AE"><span class="toc-number">13.3.</span> <span class="toc-text">接收数据</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#scapy-%E6%A8%A1%E6%8B%9F"><span class="toc-number">13.4.</span> <span class="toc-text">scapy 模拟</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8D%B1%E5%AE%B3"><span class="toc-number">13.5.</span> <span class="toc-text">危害</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%A6%82%E4%BD%95%E8%A7%A3%E5%86%B3-SYN-Flood-%E6%94%BB%E5%87%BB"><span class="toc-number">13.5.1.</span> <span class="toc-text">如何解决 SYN Flood 攻击</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#SYN-Cookie"><span class="toc-number">13.5.2.</span> <span class="toc-text">SYN Cookie</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#SYN-Cookie-%E5%8E%9F%E7%90%86"><span class="toc-number">13.5.3.</span> <span class="toc-text">SYN Cookie 原理</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Cookie-%E5%80%BC%E8%AE%A1%E7%AE%97%E7%9A%84%E8%A7%84%E5%88%99"><span class="toc-number">13.5.4.</span> <span class="toc-text">Cookie 值计算的规则</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#SYN-Cookie-%E7%9A%84%E7%BC%BA%E9%99%B7"><span class="toc-number">13.5.5.</span> <span class="toc-text">SYN Cookie 的缺陷</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#SOCKET-%E9%80%89%E9%A1%B9"><span class="toc-number">14.</span> <span class="toc-text">SOCKET 选项</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#SO-REUSEADDR"><span class="toc-number">14.1.</span> <span class="toc-text">SO_REUSEADDR</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%9A%E5%B8%B8%E4%B8%8D%E4%BC%9A%E5%9C%A8%E5%AE%A2%E6%88%B7%E7%AB%AF%E4%B8%8A%E5%87%BA%E7%8E%B0"><span class="toc-number">14.1.1.</span> <span class="toc-text">为什么通常不会在客户端上出现</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%80%BB%E7%BB%93"><span class="toc-number">14.1.2.</span> <span class="toc-text">总结</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#SO-LINGER"><span class="toc-number">14.2.</span> <span class="toc-text">SO_LINGER</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3-%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6"><span class="toc-number">15.</span> <span class="toc-text">滑动窗口 - 流量控制</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%8E%A5%E6%94%B6%E7%AA%97%E5%8F%A3-rwnd"><span class="toc-number">15.1.</span> <span class="toc-text">接收窗口 rwnd</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8F%91%E9%80%81%E7%AA%97%E5%8F%A3%E4%B8%8E%E6%8E%A5%E6%94%B6%E7%AA%97%E5%8F%A3"><span class="toc-number">15.2.</span> <span class="toc-text">发送窗口与接收窗口</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#TCP-%E5%8C%85%E7%8A%B6%E6%80%81%E5%88%86%E7%B1%BB"><span class="toc-number">15.3.</span> <span class="toc-text">TCP 包状态分类</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8F%91%E9%80%81%E7%AA%97%E5%8F%A3-send-window-%E4%B8%8E%E5%8F%AF%E7%94%A8%E7%AA%97%E5%8F%A3-uable-window"><span class="toc-number">15.4.</span> <span class="toc-text">发送窗口(send window)与可用窗口(uable window)</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#TCP-Zero-Window"><span class="toc-number">15.5.</span> <span class="toc-text">TCP Zero Window</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#Nagle-%E7%AE%97%E6%B3%95"><span class="toc-number">16.</span> <span class="toc-text">Nagle 算法</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#Nagle-%E7%AE%97%E6%B3%95%E7%9A%84%E6%84%8F%E4%B9%89"><span class="toc-number">16.1.</span> <span class="toc-text">Nagle 算法的意义</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Nagle-%E7%AE%97%E6%B3%95%E7%9A%84%E5%B1%80%E9%99%90%E6%80%A7"><span class="toc-number">16.2.</span> <span class="toc-text">Nagle 算法的局限性</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Nagle-%E6%80%BB%E7%BB%93"><span class="toc-number">16.3.</span> <span class="toc-text">Nagle 总结</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%BB%B6%E8%BF%9F%E7%A1%AE%E8%AE%A4-delayed-ack"><span class="toc-number">17.</span> <span class="toc-text">延迟确认 - delayed ack</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#TCP-%E6%8B%A5%E5%A1%9E%E6%8E%A7%E5%88%B6"><span class="toc-number">18.</span> <span class="toc-text">TCP 拥塞控制</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%85%A2%E5%90%AF%E5%8A%A8"><span class="toc-number">18.1.</span> <span class="toc-text">慢启动</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%8B%A5%E5%A1%9E%E9%81%BF%E5%85%8D"><span class="toc-number">18.2.</span> <span class="toc-text">拥塞避免</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%85%A2%E5%90%AF%E5%8A%A8-vs-%E6%8B%A5%E5%A1%9E%E9%81%BF%E5%85%8D"><span class="toc-number">18.2.1.</span> <span class="toc-text">慢启动 vs 拥塞避免</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%BF%AB%E9%80%9F%E9%87%8D%E4%BC%A0"><span class="toc-number">18.3.</span> <span class="toc-text">快速重传</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%BF%AB%E9%80%9F%E6%81%A2%E5%A4%8D"><span class="toc-number">18.4.</span> <span class="toc-text">快速恢复</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#HTTP-%E5%8D%8F%E8%AE%AE"><span class="toc-number">19.</span> <span class="toc-text">HTTP 协议</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%8A%A5%E6%96%87%E7%BB%93%E6%9E%84"><span class="toc-number">19.1.</span> <span class="toc-text">报文结构</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%A6%82%E4%BD%95%E7%94%A8-TCP-%E5%8F%91%E9%80%81-HTTP-%E8%AF%B7%E6%B1%82"><span class="toc-number">19.2.</span> <span class="toc-text">如何用 TCP 发送 HTTP 请求</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%AF%B7%E6%B1%82%E8%A1%8C"><span class="toc-number">19.2.1.</span> <span class="toc-text">请求行</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%8A%B6%E6%80%81%E8%A1%8C"><span class="toc-number">19.2.2.</span> <span class="toc-text">状态行</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%A4%B4%E9%83%A8"><span class="toc-number">19.2.3.</span> <span class="toc-text">头部</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%AF%B7%E6%B1%82%E6%96%B9%E6%B3%95"><span class="toc-number">19.3.</span> <span class="toc-text">请求方法</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%94%A8-HEAD-%E5%88%A4%E6%96%ADurl%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8"><span class="toc-number">19.3.1.</span> <span class="toc-text">用 HEAD 判断url是否存在</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%8A%B6%E6%80%81%E7%A0%81"><span class="toc-number">19.4.</span> <span class="toc-text">状态码</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Connection-%E5%A4%B4%E9%83%A8"><span class="toc-number">19.5.</span> <span class="toc-text">Connection 头部</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#HTTP2-%E5%8D%8F%E8%AE%AE"><span class="toc-number">20.</span> <span class="toc-text">HTTP2 协议</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#HTTP-x2F-1-1%E6%97%B6%E4%BB%A3%E7%9A%84%E4%BC%98%E5%8C%96"><span class="toc-number">20.1.</span> <span class="toc-text">HTTP&#x2F;1.1时代的优化</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#HTTP-x2F-2%E6%97%B6%E4%BB%A3"><span class="toc-number">20.2.</span> <span class="toc-text">HTTP&#x2F;2时代</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%A4%9A%E8%B7%AF%E5%A4%8D%E7%94%A8%E4%BB%A3%E6%9B%BF%E5%90%8C%E6%AD%A5%E8%AF%B7%E6%B1%82"><span class="toc-number">20.2.1.</span> <span class="toc-text">多路复用代替同步请求</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#HTTP-x2F-2%E7%9A%84%E4%BC%98%E5%8A%BF"><span class="toc-number">20.3.</span> <span class="toc-text">HTTP&#x2F;2的优势</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BC%98%E5%85%88%E7%BA%A7"><span class="toc-number">20.4.</span> <span class="toc-text">优先级</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%A6%96%E9%83%A8%E5%8E%8B%E7%BC%A9"><span class="toc-number">20.5.</span> <span class="toc-text">首部压缩</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#HPACK"><span class="toc-number">20.5.1.</span> <span class="toc-text">HPACK</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%9D%99%E6%80%81%E8%A1%A8"><span class="toc-number">20.5.1.1.</span> <span class="toc-text">静态表</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%8A%A8%E6%80%81%E8%A1%A8"><span class="toc-number">20.5.1.2.</span> <span class="toc-text">动态表</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#huffman%E8%A1%A8-%E6%9C%80%E4%BC%98%E5%89%8D%E7%BC%80%E7%BC%96%E7%A0%81"><span class="toc-number">20.5.1.3.</span> <span class="toc-text">huffman表 (最优前缀编码)</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#websocket-%E5%8D%8F%E8%AE%AE"><span class="toc-number">21.</span> <span class="toc-text">websocket 协议</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%B8%A7%E7%B1%BB%E5%9E%8B"><span class="toc-number">21.1.</span> <span class="toc-text">帧类型</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%8F%A1%E6%89%8B%E5%8D%8F%E8%AE%AE"><span class="toc-number">21.2.</span> <span class="toc-text">握手协议</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%80%BB%E7%BB%93-1"><span class="toc-number">21.3.</span> <span class="toc-text">总结</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#tcpdump"><span class="toc-number">22.</span> <span class="toc-text">tcpdump</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%8C%87%E5%AE%9A%E7%BD%91%E5%8D%A1"><span class="toc-number">22.1.</span> <span class="toc-text">指定网卡</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%BF%87%E6%BB%A4%E4%B8%BB%E6%9C%BA"><span class="toc-number">22.2.</span> <span class="toc-text">过滤主机</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%BF%87%E6%BB%A4%E7%AB%AF%E5%8F%A3"><span class="toc-number">22.3.</span> <span class="toc-text">过滤端口</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%A6%81%E7%94%A8%E4%B8%BB%E6%9C%BA%E4%B8%8E%E7%AB%AF%E5%8F%A3%E8%A7%A3%E6%9E%90"><span class="toc-number">22.4.</span> <span class="toc-text">禁用主机与端口解析</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%BF%87%E6%BB%A4%E5%8D%8F%E8%AE%AE"><span class="toc-number">22.5.</span> <span class="toc-text">过滤协议</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%9F%A5%E7%9C%8B%E5%8C%85%E4%BD%93%E5%86%85%E5%AE%B9"><span class="toc-number">22.6.</span> <span class="toc-text">查看包体内容</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%99%90%E5%88%B6%E5%8C%85%E5%A4%A7%E5%B0%8F"><span class="toc-number">22.7.</span> <span class="toc-text">限制包大小</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%8A%93%E5%8F%96%E7%89%B9%E5%AE%9A%E6%95%B0%E9%87%8F%E7%9A%84%E5%8C%85"><span class="toc-number">22.8.</span> <span class="toc-text">抓取特定数量的包</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%95%B0%E6%8D%AE%E6%8A%A5%E6%96%87%E8%BE%93%E5%87%BA%E5%88%B0%E6%96%87%E4%BB%B6"><span class="toc-number">22.9.</span> <span class="toc-text">数据报文输出到文件</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%98%BE%E7%A4%BA%E7%BB%9D%E5%AF%B9%E7%9A%84%E5%BA%8F%E5%8F%B7"><span class="toc-number">22.10.</span> <span class="toc-text">显示绝对的序号</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%AB%98%E7%BA%A7%E6%8A%80%E5%B7%A7"><span class="toc-number">22.11.</span> <span class="toc-text">高级技巧</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%B8%B8%E7%94%A8%E7%BD%91%E7%BB%9C%E5%B7%A5%E5%85%B7"><span class="toc-number">23.</span> <span class="toc-text">常用网络工具</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#telnet"><span class="toc-number">23.1.</span> <span class="toc-text">telnet</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%A3%80%E6%9F%A5%E7%AB%AF%E5%8F%A3%E6%98%AF%E5%90%A6%E6%89%93%E5%BC%80"><span class="toc-number">23.1.1.</span> <span class="toc-text">检查端口是否打开</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#telnet-%E5%8F%91%E9%80%81-http-%E8%AF%B7%E6%B1%82"><span class="toc-number">23.1.2.</span> <span class="toc-text">telnet 发送 http 请求</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#telnet-%E8%BF%9E%E6%8E%A5-Redis"><span class="toc-number">23.1.3.</span> <span class="toc-text">telnet 连接 Redis</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#nc"><span class="toc-number">23.2.</span> <span class="toc-text">nc</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%94%A8-nc-%E5%85%85%E5%BD%93%E7%BD%91%E7%BB%9C%E8%81%8A%E5%A4%A9%E5%99%A8"><span class="toc-number">23.2.1.</span> <span class="toc-text">用 nc 充当网络聊天器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8F%91%E9%80%81-http-%E8%AF%B7%E6%B1%82"><span class="toc-number">23.2.2.</span> <span class="toc-text">发送 http 请求</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%9F%A5%E7%9C%8B%E8%BF%9C%E7%A8%8B%E7%AB%AF%E5%8F%A3%E6%98%AF%E5%90%A6%E6%89%93%E5%BC%80"><span class="toc-number">23.2.3.</span> <span class="toc-text">查看远程端口是否打开</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#netstat"><span class="toc-number">23.3.</span> <span class="toc-text">netstat</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%88%97%E5%87%BA%E6%89%80%E6%9C%89%E7%9A%84%E5%A5%97%E6%8E%A5%E5%AD%97"><span class="toc-number">23.3.1.</span> <span class="toc-text">列出所有的套接字</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8F%AA%E5%88%97%E5%87%BA-TCP-%E5%A5%97%E6%8E%A5%E5%AD%97"><span class="toc-number">23.3.2.</span> <span class="toc-text">只列出 TCP 套接字</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8F%AA%E5%88%97%E5%87%BA-UDP-%E5%A5%97%E6%8E%A5%E5%AD%97"><span class="toc-number">23.3.3.</span> <span class="toc-text">只列出 UDP 套接字</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8F%AA%E5%88%97%E5%87%BA%E5%A4%84%E4%BA%8E-listen-%E7%8A%B6%E6%80%81%E7%9A%84%E8%BF%9E%E6%8E%A5"><span class="toc-number">23.3.4.</span> <span class="toc-text">只列出处于 listen 状态的连接</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%A6%81%E7%94%A8%E7%AB%AF%E5%8F%A3%E5%92%8CIP%E6%98%A0%E5%B0%84"><span class="toc-number">23.3.5.</span> <span class="toc-text">禁用端口和IP映射</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%98%BE%E7%A4%BA%E8%BF%9B%E7%A8%8B"><span class="toc-number">23.3.6.</span> <span class="toc-text">显示进程</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%98%BE%E7%A4%BA%E6%89%80%E6%9C%89%E7%9A%84%E7%BD%91%E5%8D%A1%E4%BF%A1%E6%81%AF"><span class="toc-number">23.3.7.</span> <span class="toc-text">显示所有的网卡信息</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BB%9F%E8%AE%A1%E5%A4%84%E4%BA%8E%E5%90%84%E4%B8%AA%E7%8A%B6%E6%80%81%E7%9A%84%E8%BF%9E%E6%8E%A5%E4%B8%AA%E6%95%B0"><span class="toc-number">23.3.8.</span> <span class="toc-text">统计处于各个状态的连接个数</span></a></li></ol></li></ol></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/2024/03/12/Nmap%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/" title="Nmap使用指南"><img src="/img/cover/cover_2.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Nmap使用指南"/></a><div class="content"><a class="title" href="/2024/03/12/Nmap%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/" title="Nmap使用指南">Nmap使用指南</a><time datetime="2024-03-12T02:38:29.000Z" title="发表于 2024-03-12 10:38:29">2024-03-12</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2024/03/10/TCP%E5%8D%8F%E8%AE%AE/" title="TCP协议"><img src="/img/cover/cover_9.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="TCP协议"/></a><div class="content"><a class="title" href="/2024/03/10/TCP%E5%8D%8F%E8%AE%AE/" title="TCP协议">TCP协议</a><time datetime="2024-03-10T08:15:52.000Z" title="发表于 2024-03-10 16:15:52">2024-03-10</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2024/03/06/%E5%B8%B8%E7%94%A8%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8%E8%AE%BE%E5%A4%87/" title="常用网络安全设备"><img src="/img/cover/cover_6.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="常用网络安全设备"/></a><div class="content"><a class="title" href="/2024/03/06/%E5%B8%B8%E7%94%A8%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8%E8%AE%BE%E5%A4%87/" title="常用网络安全设备">常用网络安全设备</a><time datetime="2024-03-06T00:58:05.000Z" title="发表于 2024-03-06 08:58:05">2024-03-06</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2024/03/06/%E6%B8%97%E9%80%8F%E6%B5%8B%E8%AF%95/" title="渗透测试"><img src="/img/cover/cover_9.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="渗透测试"/></a><div class="content"><a class="title" href="/2024/03/06/%E6%B8%97%E9%80%8F%E6%B5%8B%E8%AF%95/" title="渗透测试">渗透测试</a><time datetime="2024-03-06T00:57:01.000Z" title="发表于 2024-03-06 08:57:01">2024-03-06</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2024/03/06/OWASP-TOP-10/" title="OWASP-TOP-10"><img src="/img/cover/cover_2.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="OWASP-TOP-10"/></a><div class="content"><a class="title" href="/2024/03/06/OWASP-TOP-10/" title="OWASP-TOP-10">OWASP-TOP-10</a><time datetime="2024-03-06T00:55:41.000Z" title="发表于 2024-03-06 08:55:41">2024-03-06</time></div></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2023 - 2025 By fanhao</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="回到顶部"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox/fancybox.umd.min.js"></script><div class="js-pjax"></div><script defer="defer" id="ribbon" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/dist/canvas-ribbon.min.js" size="150" alpha="0.6" zIndex="-1" mobile="true" data-click="false"></script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div></body></html>